디스크립터 (Descriptor): 키포인트 주변의 지역적인 이미지 정보를 숫자 벡터로 표현한 것.
이 벡터는 해당 키포인트의 "지문" 역할
다른 이미지에서 유사한 특징점을 찾을 때 비교에 사용
ORB (Oriented FAST and Rotated BRIEF) 특징점 검출기:
FAST 알고리즘을 이용해 키포인트 검출
BRIEF 알고리즘을 이용해 디스크립터 생성
Oriented & Rotated: 키포인트의 방향성과 디스크립터의 회전 개념을 추가
FAST
Features from Accelerated Segment Test
후보점 p 주변의 원을 이루는 픽셀 16개의 밝기를 봄
만약 연속된 9개의 픽셀이 모두 중심보다 충분히 밝거나, 모두 중심보다 충분히 어두우면 코너로 판정
Oriented FAST: FAST + 코너 방향
BRIEF
Binary Robust Independent Elementary Features
특징점 주변의 작은 패치를 가져옴
미리 정해진 픽셀 쌍들을 패치 안에서 뽑아 각 쌍에 대해 밝기 비교
비교 결과를 0/1 비트열로 저장
두 개의 특징점을 비교할 때는 비트열에서 차이를 구함
특징 디스크립터 Feature Descriptor
import cv2 as cv
import numpy as np
img1 = cv.imread('stop_sign1.jpg') # 비교할 이미지 로드
img1 = cv.resize(img1, (250, 250)) # 이미지 크기 조정
img2 = cv.imread('stop_sign2.jpg')
gray1 = cv.cvtColor(img1, cv.COLOR_BGR2GRAY) # 특징점 검출을 위해 흑백으로
gray2 = cv.cvtColor(img2, cv.COLOR_BGR2GRAY)
# ORB(Oriented FAST and Rotated BRIEF) 특징점 검출기
detector = cv.ORB_create() # 검출기 생성
kp1, desc1 = detector.detectAndCompute(gray1, None) # 각 이미지의 키포인트(kp)와
kp2, desc2 = detector.detectAndCompute(gray2, None) # 디스크립터(desc)를 추출
특징 매칭 Feature Matching
# 2개의 그림에서 특징들이 서로 일치하는 부분을 매칭
matcher = cv.BFMatcher(cv.NORM_HAMMING, crossCheck=True)
matches = matcher.match(desc1, desc2)
# 매칭된 결과를 거리의 오름차순으로 정렬(가까울수록 좋은 매칭)
matches = sorted(matches, key=lambda x: x.distance)
# 결과 시각화
res1 = cv.drawMatches(img1, kp1, img2, kp2, matches, None)
show(res1)
호모그래피 Homography
두 장의 사진이 다른 방향과 각도에서 촬영한 것이므로 완전히 일치하지는 않음
투시 변환을 통해서 방향과 각도를 맞출 수 있음(호모그래피 ≒ 투시 변환)
# 두 이미지에서 매칭된 점의 좌표들을 추출
src_pts = np.float32([ kp1[m.queryIdx].pt for m in matches ])
dst_pts = np.float32([ kp2[m.trainIdx].pt for m in matches ])
# RANSAC 알고리즘으로 두 좌표들을 최대한 맞출 수 있는 변환 행렬을 계산# (임계값 5.0 이하의 점들만 포함)
mtrx, mask = cv.findHomography(src_pts, dst_pts, cv.RANSAC, 5.0)
시각화
h, w = img1.shape[:2] # 원본 이미지 크기
pts = np.float32([[[0, 0]], [[0, h - 1]], [[w - 1, h - 1]], [[w - 1, 0]]]) # 원본 이미지의 네 모서리 좌표
dst = cv.perspectiveTransform(pts, mtrx) # img1의 네 모서리가 img2에서 어디로 변환되는지# 시각화
polyline = img2.copy()
cv.polylines(polyline, [np.int32(dst)], True, (0, 255, 0), 3, cv.LINE_AA)
show(polyline)