본문 바로가기

카테고리 없음

[OpenCV] 영상처리_매칭점 찾기

1. 올바른 매칭점 찾기

(1) match() 함수

- match()함수는 모든 디스크립터를 하나하나 비교하여 매칭점을 찾고,

- 가장 작은 거리 값과 큰 거리값의 상위 몇 퍼센트만 골라서 올바른 매칭점을 찾게 된다.

 

: 모든 디스크립터를 하나하나 비교하여 매칭점을 찾는다

: 가장 작은 거리 값과 큰 거리 값의 상위 몇 퍼센트만 골라서 올바른 매칭점을 찾을 수 있음

 

인자를 3개를 기본으로 넣어주면 되는데, 구간 시작점, 구간 끝점, 구간 내 숫자 개수 3가지를 순서대로 채워주시면 됩니다. 예를 들어 1과 10 사이를 숫자 100개(끝점 포함)로 채운 예시를 보도록 하겠습니다.

import cv2
import numpy as np

img1 = cv2.imread('img/taekwonv1.jpg')
img2 = cv2.imread('img/figures.jpg')
gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)

# 1) ORB로 서술자 추출
detector = cv2.ORB_create()
kp1, desc1 = detector.detectAndCompute(gray1, None)
kp2, desc2 = detector.detectAndCompute(gray2, None)

# 2) BF-Hamming으로 매칭
matcher = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
matches = matcher.match(desc1, desc2)

# 3) 매칭 결과를 거리기준 오름차순으로 정렬
matches = sorted(matches, key=lambda x:x.distance)

# 4) 최소 거리 값과 최대 거리 값 확보
min_dist, max_dist = matches[0].distance, matches[-1].distance

# 5) 최소 거리의 15% 지점을 임계점으로 설정
ratio = 0.2
good_thresh = (max_dist - min_dist) * ratio + min_dist

# 6) 임계점 보다 작은 매칭점만 좋은 매칭점으로 분류 
good_matches = [m for m in matches if m.distance < good_thresh]
print('matches:%d/%d, min:%.2f, max:%.2f, thresh:%.2f' \
        %(len(good_matches),len(matches), min_dist, max_dist, good_thresh))

# 7) 좋은 매칭점만 그리기
res = cv2.drawMatches(img1, kp1, img2, kp2, good_matches, None, \
                flags=cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS)

# 8) 결과 출력
cv2.imshow('Good Match', res)
cv2.waitKey()
cv2.destroyAllWindows()

match 함수로부터 찾은 매칭점

 

(2) knnMatch() 함수

- 디스크립터 당 k개의 최근접 이웃 매칭점을 가까운 순서대로 반환하는 것으로,

- k개의 최근접 이웃 거리 중 거리가 가까운 것은 좋은 매칭점이고, 거리가 먼 것은 좋지 못한 매칭점일 가능성이 높다.

- 최 근접 이웃 중 거리가 가까운 것 위주로 골라내게 되면 좋은 매칭점을 찾을 수 있음

# knnMatch 함수로부터 올바른 매칭점 찾기
import cv2, numpy as np

img1 = cv2.imread('img/taekwonv1.jpg')
img2 = cv2.imread('img/figures.jpg')
gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)

# 1) ORB로 서술자 추출
detector = cv2.ORB_create()
kp1, desc1 = detector.detectAndCompute(gray1, None)
kp2, desc2 = detector.detectAndCompute(gray2, None)

# 2) BF-Hamming 생성
matcher = cv2.BFMatcher(cv2.NORM_HAMMING2)

# 3) knnMatch, k=2
matches = matcher.knnMatch(desc1, desc2, 2)

# 4) 첫번재 이웃의 거리가 두 번째 이웃 거리의 75% 이내인 것만 추출
ratio = 0.75
good_matches = [first for first,second in matches \
                    if first.distance < second.distance * ratio]
print('matches:%d/%d' %(len(good_matches),len(matches)))

# 5) 좋은 매칭만 그리기
res = cv2.drawMatches(img1, kp1, img2, kp2, good_matches, None, \
                    flags=cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS)
# 결과 출력                    
cv2.imshow('Matching', res)
cv2.waitKey()
cv2.destroyAllWindows()

- 최근접 이웃 중 거리가 가까운 것 중 75%만 고름