귀퉁이 서재

OpenCV - 27. 특징 디스크립터 검출기 (SIFT, SURF, ORB) 본문

OpenCV

OpenCV - 27. 특징 디스크립터 검출기 (SIFT, SURF, ORB)

Baek Kyun Shin 2020. 11. 9. 22:41

이번 포스팅에서는 특징 디스크립터 검출기에 대해 알아보겠습니다. 이번 포스팅 역시 '파이썬으로 만드는 OpenCV 프로젝트(이세우 저)'를 정리한 것임을 밝힙니다.

코드: github.com/BaekKyunShin/OpenCV_Project_Python/tree/master/08.match_track

이전 포스팅에서 설명했다시피 특징점이란 말 그대로 이미지에서 특징이 되는 부분을 의미합니다. 이미지끼리 서로 매칭이 되는지 확인을 할 때 각 이미지에서의 특징이 되는 부분끼리 비교를 합니다. 즉, 이미지 매칭 시 사용하는 것이 바로 특징점입니다. 특징점은 영어로 키 포인트(Keypoints)라고도 합니다.

특징 디스크립터

이 특징점은 객체의 좌표뿐만 아니라 그 주변 픽셀과의 관계에 대한 정보를 가집니다. 그중 가장 대표적인 것이 size와 angle 속성이며, 코너(corner)점인 경우 코너의 경사도와 방향도 속성으로 가집니다. 특징 디스크립터(feature descriptor)란 특징점 주변 픽셀을 일정한 크기의 블록으로 나누어 각 블록에 속한 픽셀의 그레디언트 히스토그램을 계산한 것입니다. 주로 특징점 주변의 밝기, 색상, 방향, 크기 등의 정보가 포함되어 있습니다. 추출하는 알고리즘에 따라 특징 디스크립터가 일부 달라질 수는 있습니다. 일반적으로 특징점 주변의 블록 크기에 8방향(상, 하, 좌, 우 및 네 방향의 대각선) 경사도를 표현하는 경우가 많습니다. 4 x 4 크기의 블록인 경우 한 개의 특징점당 4 x 4 x 8 = 128개의 값을 갖습니다.

OpenCV는 특징 디스크립터를 추출하기 위해 다음과 같은 함수를 제공합니다.

  • keypoints, descriptors = detector.compute(image, keypoins, descriptors): 특징점을 전달하면 특징 디스크립터를 계산해서 반환
  • keypoints, descriptors = detector.detectAndCompute(image, mask, decriptors, useProvidedKeypoints): 특징점 검출과 특징 디스크립터 계산을 한 번에 수행
    image: 입력 이미지
    keypoints: 디스크립터 계산을 위해 사용할 특징점
    descriptors(optional): 계산된 디스크립터
    mask(optional)
    : 특징점 검출에 사용할 마스크
    useProvidedKeypoints(optional): True인 경우 특징점 검출을 수행하지 않음

이전 포스팅에서 소개했던 각종 특징점 검출기를 통해 특징점을 검출한 경우에는 detector.compute() 함수를 사용해서 특징 디스크립터를 구할 수 있습니다. detector.compute() 함수의 keypoints 파라미터에 특징점을 전달해주면 됩니다. 반면 detector.detectAndCompute() 함수는 특징점과 특징 디스크립터를 동시에 계산해줍니다. 따라서 특징점 검출기로 특징점을 한번 검출하고, 그다음 detector.compute() 함수를 사용하는 것보다 처음부터 detector.detectAndCompute() 함수를 사용하는 게 더 편리하겠죠.

이제 소개할 SIFT, SURF, ORB는 모두 특징 디스크립터를 구해주는 알고리즘입니다.

SIFT (Scale-Invariant Feature Transform)

기존의 해리스 코너 검출 알고리즘은 크기 변화에 민감한 문제를 가지고 있었습니다. SIFT는 이미지 피라미드를 이용해서 크기 변화에 따른 특징점 검출 문제를 해결한 알고리즘입니다. OpenCV에서 제공하는 SIFT 객체 생성자는 다음과 같습니다.

  • detector = cv2.xfeatures2d.SIFT_create(nfeatures, nOctaveLayers, contrastThreshold, edgeThreshold, sigma)
    nfeatures: 검출 최대 특징 수
    nOctaveLayers: 이미지 피라미드에 사용할 계층 수
    contrastThreshold: 필터링할 빈약한 특징 문턱 값
    edgeThreshold: 필터링할 엣지 문턱 값
    sigma: 이미지 피라미드 0 계층에서 사용할 가우시안 필터의 시그마 값
# SIFT로 특징점 및 디스크립터 추출(desc_sift.py)

import cv2
import numpy as np

img = cv2.imread('../img/house.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# SIFT 추출기 생성
sift = cv2.xfeatures2d.SIFT_create()
# 키 포인트 검출과 서술자 계산
keypoints, descriptor = sift.detectAndCompute(gray, None)
print('keypoint:',len(keypoints), 'descriptor:', descriptor.shape)
print(descriptor)

# 키 포인트 그리기
img_draw = cv2.drawKeypoints(img, keypoints, None, \
                flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
# 결과 출력
cv2.imshow('SIFT', img_draw)
cv2.waitKey()
cv2.destroyAllWindows()

출력된 결과를 보시면 특징점이 총 413개임을 알 수 있습니다. 그리고 특징점 1개 당 128개의 특징 디스크립터 값을 사용하는 것을 알 수 있습니다.

SURF (Speeded Up Robust Features)

SIFT는 크기 변화에 따른 특징 검출 문제를 해결하기 위해 이미지 피라미드를 사용하므로 속도가 느리다는 단점이 있습니다. SURF는 이미지 피라미드 대신 필터의 크기를 변화시키는 방식으로 성능을 개선한 알고리즘입니다. SURF는 아래와 같이 생성할 수 있습니다.

  • detector = cv2.xfeatures2d.SURF_create(hessianThreshold, nOctaves, nOctaveLayers, extended, upright)
    hessianThreshold(optional): 특징 추출 경계 값 (default=100)
    nOctaves(optional): 이미지 피라미드 계층 수 (default=3)
    extended(optional): 디스크립터 생성 플래그 (default=False), True: 128개, False: 64개
    upright(optional): 방향 계산 플래그 (default=False), True: 방향 무시, False: 방향 적용
# SURF로 특징점 및 특징 디스크립터 추출 (desc_surf.py)

import cv2
import numpy as np

img = cv2.imread('../img/house.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# SURF 추출기 생성 ( 경계:1000, 피라미드:3, 서술자확장:True, 방향적용:True)
surf = cv2.xfeatures2d.SURF_create(1000, 3, True, True)
# 키 포인트 검출 및 서술자 계산
keypoints, desc = surf.detectAndCompute(gray, None)
print(desc.shape, desc)
# 키포인트 이미지에 그리기
img_draw = cv2.drawKeypoints(img, keypoints, None, \
                flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)

cv2.imshow('SURF', img_draw)
cv2.waitKey()
cv2.destroyAllWindows()

총 104개의 특징점과 각 특징점마다 128개의 디스크립터 값을 사용하는 것을 알 수 있습니다.

ORB (Oriented and Rotated BRIEF)

디스크립터 검출기 중 BRIEF(Binary Robust Independent Elementary Features)라는 것이 있습니다. BRIEF는 특징점 검출은 지원하지 않는 디스크립터 추출기입니다. 이 BRIEF에 방향과 회전을 고려하도록 개선한 알고리즘이 바로 ORB입니다. 이 알고리즘은 특징점 검출 알고리즘으로 FAST를 사용하고 회전과 방향을 고려하도록 개선했으며 속도도 빨라 SIFT와 SURF의 좋은 대안으로 사용됩니다. ORB 객체 생성은 다음과 같이 합니다.

  • detector = cv2.ORB_create(nfeatures, scaleFactor, nlevels, edgeThreshold, firstLevel, WTA_K, scoreType, patchSize, fastThreshold)
    nfeatures(optional): 검출할 최대 특징 수 (default=500)
    scaleFactor(optional): 이미지 피라미드 비율 (default=1.2)
    nlevels(optional): 이미지 피라미드 계층 수 (default=8)
    edgeThreshold(optional): 검색에서 제외할 테두리 크기, patchSize와 맞출 것 (default=31)
    firstLevel(optional): 최초 이미지 피라미드 계층 단계 (default=0)
    WTA_K(optional): 임의 좌표 생성 수 (default=2)
    scoreType(optional): 특징점 검출에 사용할 방식 (cv2.ORB_HARRIS_SCORE: 해리스 코너 검출(default), cv2.ORB_FAST_SCORE: FAST 코너 검출)
    patchSize(optional): 디스크립터의 패치 크기 (default=31)
    fastThreshold(optional): FAST에 사용할 임계 값 (default=20)

ORB를 활용해 특징점 및 특징 디스크립터를 검출해보겠습니다.

# ORB로 특징점 및 특징 디스크립터 검출 (desc_orb.py)

import cv2
import numpy as np

img = cv2.imread('../img/house.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# ORB 추출기 생성
orb = cv2.ORB_create()
# 키 포인트 검출과 서술자 계산
keypoints, descriptor = orb.detectAndCompute(img, None)
# 키 포인트 그리기
img_draw = cv2.drawKeypoints(img, keypoints, None, \
             flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
# 결과 출력
cv2.imshow('ORB', img_draw)
cv2.waitKey()
cv2.destroyAllWindows()

 

Comments