이전 포스팅에서 특징점을 매칭하는 방법에 대해 공부해보았습니다.
하지만 결과값이 너무 복잡하여 매칭이 잘 되었는지 확인하는 것에 어려움이 있었습니다.
이번에는 좋은 매칭을 선별하는 두 가지 방법에 대해 공부해보겠습니다.
좋은 매칭 선별
좋은 매칭 선별 방법 두 가지를 알아보겠습니다.
1. distance 값을 기준으로 정렬 후 상위 N개 선택하기
가장 좋은 매칭 결과에서 distance 값이 작은 것 N개를 사용하는 방법입니다.
유사도가 높은 것이 좋은 매칭을 의미하는데 유사도가 높다는 것은 두 개의 특징벡터의 distance 값이 작은 것을 말합니다.
cv2.DMatch.distance 값을 기준으로 내림차순 정렬 후 상위 N개를 선택합니다.
예제 코드는 KAZE 특징점 검출 방법을 이용했습니다.
# 영상 불러오기
src1 = cv2.imread('graf1.png', cv2.IMREAD_GRAYSCALE)
src2 = cv2.imread('graf3.png', cv2.IMREAD_GRAYSCALE)
if src1 is None or src2 is None:
print('Image load failed!')
sys.exit()
# 특징점 알고리즘 객체 생성 (KAZE, AKAZE, ORB 등)
frature = cv2.KAZE_create()
# feature = cv2.AKAZE_create()
# feature = cv2.ORB_create()
# 특징점 검출 및 기술자 계산
kp1, desc1 = feature.detectAndCompute(src1, None)
kp2, desc2 = feature.detectAndCompute(src2, None)
# 특징점 매칭
matcher = cv2.BFMatcher_create()
#matcher = cv2.BFMatcher_create(cv2.NORM_HAMMING) # 이진 기술자
matches = matcher.match(desc1, desc2)
# 좋은 매칭 결과 선별, sort 기준을 distance 값으로 설정
matches = sorted(matches, key=lambda x: x.distance)
good_matches = matches[:80] # 상위 80개 선별
print('# of kp1:', len(kp1))
print('# of kp2:', len(kp2))
print('# of matches:', len(matches))
print('# of good_matches:', len(good_matches))
# 특징점 매칭 결과 영상 생성
dst = cv2.drawMatches(src1, kp1, src2, kp2, good_matches, None)
cv2.namedWindow('dst',cv2.WINDOW_NORMAL)
cv2.imshow('dst', dst)
cv2.waitKey()
cv2.destroyAllWindows()
2. 가장 좋은 값과 두 번째로 좋은 값의 비율을 계산하기
가장 좋은 매칭 결과의 distance 값과 두 번째로 좋은 매칭 결과의 distance 값의 비율을 계산하는 방법입니다.
비율의 임계값을 설정하여 임계값보다 작으면 선택함으로써 좋은 매칭 결과를 선별할 수 있습니다.
예제코드는 ORB 특징점 검출 방법을 이용했습니다.
두 개의 특징점을 검출해야 하므로 knnMatch를 이용하였고 k 인자에 2의 값을 주었습니다.
# 영상 불러오기
src1 = cv2.imread('graf1.png', cv2.IMREAD_GRAYSCALE)
src2 = cv2.imread('graf3.png', cv2.IMREAD_GRAYSCALE)
if src1 is None or src2 is None:
print('Image load failed!')
sys.exit()
# 특징점 알고리즘 객체 생성 (KAZE, AKAZE, ORB 등)
# feature = cv2.KAZE_create()
#feature = cv2.AKAZE_create()
feature = cv2.ORB_create()
# 특징점 검출 및 기술자 계산
kp1, desc1 = feature.detectAndCompute(src1, None)
kp2, desc2 = feature.detectAndCompute(src2, None)
# 특징점 매칭
# matcher = cv2.BFMatcher_create()
matcher = cv2.BFMatcher_create(cv2.NORM_HAMMING)
matches = matcher.knnMatch(desc1, desc2, 2) # knnMatch로 특징점 2개 검출
# 좋은 매칭 결과 선별
good_matches = []
for m in matches: # matches는 두개의 리스트로 구성
if m[0].distance / m[1].distance < 0.7: # 임계점 0.7
good_matches.append(m[0]) # 저장
print('# of kp1:', len(kp1))
print('# of kp2:', len(kp2))
print('# of matches:', len(matches))
print('# of good_matches:', len(good_matches))
# 특징점 매칭 결과 영상 생성
dst = cv2.drawMatches(src1, kp1, src2, kp2, good_matches, None)
cv2.imshow('dst', dst)
cv2.waitKey()
cv2.destroyAllWindows()
ORB 기본값은 특징점 500개 검출이므로 500개의 특징점이 검출되었습니다.
비율이 0.7 이상에 해당하는 특징점은 37개 입니다.
ORB 방법이 성능이 제일 떨어지지만 제일 빠릅니다.
AKAZE가 성능이 제일 좋습니다.
모든 매칭 결과를 사용하는 것이 아니라 잘된 매칭 결과만을 이용합니다.
잘못된 매칭 결과가 남아 있을 수 있는데 그것들을 또 걸러내는 방법을 다음 포스팅에서 알아보겠습니다.
OpenCV 튜토리얼과 황선규 박사님의 'OpenCV 4로 배우는 컴퓨터 비전과 머신 러닝' 을 공부하면서 정리해 보았습니다.