이전 글에서 살펴본 매칭은 영상 전체를 바탕으로 비교하는 방법이기 때문에 비교할 영상이 비슷할 때만 좋은 결과가 나타난다. 즉, 물체의 변환이 있거나 회전이 있으면 좋은 결과를 얻을 수 없는 단점을 지닌다. pixel의 변화가 급격하게 일어나는 곳의 코너에 초점을 두어 영상 속의 여러 특징을 얻어내는 것이 필요하다.

 

1. Harris 코너 검출

Harris 코너 검출은 Sobel 필터로 edge를 찾아낸 다음, Gradiant 변화량을 측정해서 x축과 y축으로 동시에 급격하게 변화한 지점을 코너로 판단한다.

import cv2
import numpy as np

img = cv2.imread('weapon/search/vector.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# Harris corner 검출
corner = cv2.cornerHarris(gray, 2, 3, 0.05)
img[corner > 0.01 * corner.max()] = [0,255,0]

# 정규화
corner_norm = cv2.normalize(corner, None, 0, 255, cv2.NORM_MINMAX, cv2.CV_8U)

cv2.imshow('Harris', img)
cv2.imshow('corner', corner_norm)
cv2.waitKey()
cv2.destroyAllWindows()

코너 검출 후 정규화한 이미지(좌) / 가장 밝은 지점을 원으로 표시한 이미지(우)

cv2.cornerHarris로 흑백으로 변환된 이미지의 corner를 검출한 후, 코너가 이미지에 표시되도록 한다. 코너 최댓값에 곱하는 상수를 조절하면서 다른 결과를 도출할 수 있다. 코너가 검출된 결과를 확인하기 위해 cv2.normalize를 사용해 pixel 범위인 0부터 255 사이의 범위로 정규화를 진행한다. 정규화 과정에서 cv2.CV_8U로 8비트 이진 변환을 하지 않으면 corner 이미지를 출력할 때 흰 바탕의 이미지만 나타나게 되니 주의해야 한다. 코너 검출을 수행하는 cv2.cornerHarris는 입력 영상, 이웃한 pixel의 범위, Sobel 커널 크기, 코너 검출 상수, [검출 결과, 외곽 보정 방법]이 인자로 사용된다. 검출 결과는 입력 영상과 같은 크기의 1차원 배열로 반환되며, 최댓값이 코너가 된다. 

 

2. Shi-Tomasi 코너 검출

Harris 검출 방법을 개선한 것으로 cv2.goodFeaturesToTrack() 함수로 코너 검출을 수행한다.

import cv2
import numpy as np

img = cv2.imread('weapon/search/vector.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# Shi-Tomasi corner 검출
corner = cv2.goodFeaturesToTrack(gray, 80, 0.01, 10)

# 코너에 원  표시
for dot in corner:
    x, y = dot[0]
    cv2.circle(img, (x, y), 3, (0,255,0), 1, cv2.LINE_AA)
    
cv2.imshow('Shi-Tomasi', img)
cv2.imshow('corner', corner_norm)
cv2.waitKey()
cv2.destroyAllWindows()

cv2.goodFeaturesToTrack()는 입력 영상, 획득할 코너 개수, 코너로 판단할 임계값, 코너 간 최소 거리, [검출 결과, 검출에 제외할 마스크, 코너 주변 영역 크기, 코너 검출 방법, 해리스 코너 검출에 사용할 계수]이 인자로 사용된다. 코너 주변 영역 크기의 default값은 3, 코너 검출 방법은 default로 False(Shi-Tomasi 검출방법)이 설정된다. 검출 방법을 True로 지정하면 Harris 검출법으로 작동된다. 코너 좌표의 배열로 결과가 반환된다.

 

3. GFTTDetector(Great Feature To Track)

import cv2
import numpy as np

img = cv2.imread('weapon/search/vector.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# Good Feature to Track 검출기 생성
gftt = cv2.GFTTDetector_create()

# keypoint 검출
point = gftt.detect(gray, None)

# keypoint 그리기
draw = cv2.drawKeypoints(img, point, None)
# draw = cv2.drawKeypoints(img, point, None, (0,0,255))

cv2.imshow('GFTTDetector', draw)
cv2.waitKey()
cv2.destroyAllWindows()

더 좋은 feature를 찾아내기 위해 GFTT(Good Feature to Track) 검출기를 사용한다. GFTT 검출기를 생성하는 cv2.GFTTDetector_create() 인자는 [획득할 코너 개수, 코너로 판단할 임계값, 코너 간 최소 거리, 코너 주변 영역 크기, 코너 검출 방법, 해리스 코너 검출에 사용할 계수]이 인자로 사용된다. 인자의 모든 내용 및 사용방법은 Shi-Tomasi를 사용하는 cv2.goodFeaturesToTrack()과 같다. keypoint를 검출하는 detect() 함수의 인자로는 입력 영상, [검출에 제외할 마스크]가 사용된다. 검출한 keypoint(특징 점)를 표시하는 함수로 cv2.drawKeypoints()는 입력 영상, keypoint 리스트, 결과 영상, [색상, 표시 방법]이 인자로 사용된다. 색상은 랜덤이 default이며, 표시 방법은 좌표 중심에 원이 나타나도록 한다. cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS를 입력하면 영상 비율에 고려해서 원의 크기가 조정되어 표시된다. 출력 결과와 같이 난잡한 색상을 원하지 않는다면, 코드 부분에서 주석이 달린 부분을 사용하면 된다.

 

4. FAST

import cv2
import numpy as np

img = cv2.imread('weapon/search/vector.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# FAST 검출기 생성
fast = cv2.FastFeatureDetector_create(50)

# keypoint 검출 및 그리기
point = fast.detect(gray, None)
draw = cv2.drawKeypoints(img, point, None)

cv2.imshow('FAST', draw)
cv2.waitKey()
cv2.destroyAllWindows()

본래 명칭은 Feature from Accelerated Segment Test이며, 이름과 같이 feature를 검출하는 속도를 개선한 것이다.코너 판단 여부는 pixel을 중심으로 원을 그려서 임계값을 기준으로 특정 개수 이상이 밝거나 어두움이 연속될 때를 기준으로 결정된다. FAST 검출기를 생성하는 cv2.FastFeatureDetector_create()는 임계값, [코너 억제 여부, edge 검출 패턴]을 인자로 사용한다. 선명한 edge를 찾기 위해서 코너 억제 여부의 default는 True로 설정된다. edge 검출 패턴은 해당 pixel 주변의 16개에 대해 9개의 pixel이 임계를 만족하는지에 대해 비교하는 cv2.FastFeatureDetector_TYPE_9_16이 default로 적용된다.

 

5. SimpleBlobDetector

BLOB이란 Binary Large Object의 줄임말로, 이진 이미지의 연결된 pixel 그룹을 의미한다. 작은 객체는 Noise로 판단해서 무시하고, 특정 크기 이상의 객체에만 관심을 가진다. cv2.SimpleBlobDetector_create()로 BLOB 검출기를 생성한다. 아무 인자 없이 BLOB 검출을 할 수도 있지만, cv2.SimpleBlobDetector_Params()로 필요한 옵션만 골라서 검출할 수도 있다.

# ver.No Params
import cv2
import numpy as np

img = cv2.imread('weapon/search/vector.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# BLOB 검출기 생성
sbd = cv2.SimpleBlobDetector_create()

point = sbd.detect(gray, None)
draw = cv2.drawKeypoints(img, point, None, (0,0,255), flags = cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)

cv2.imshow('SBD', draw)
cv2.waitKey()
cv2.destroyAllWindows()

위 코드는 옵션 인자를 포함하지 않고 BLOB 검출을 수행한 것이다. 옵션을 포함한 BLOB 검출은 아래 코드 및 설명을 참고한다.

# ver. Params
import cv2
import numpy as np

img = cv2.imread('weapon/search/vector.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

sbd = cv2.SimpleBlobDetector_create()
point = sbd.detect(gray, None)

# params 추가
params = cv2.SimpleBlobDetector_Params()
params.maxThreshold = 200
params.filterByConvexity = False

sbd = cv2.SimpleBlobDetector_create(params)
point = sbd.detect(gray, None)
draw = cv2.drawKeypoints(img, point, None, (0,255,0), flags = cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
cv2.imshow('SBD', draw)
cv2.waitKey()
cv2.destroyAllWindows()

cv2.SimpleBlobDetector_Params()의 옵션 종류는 다음과 같다.

blobColor 0 = 흑색 Blob 검출 / 255 = 백색 Blob 검출
filterByArea 면적 필터 옵션
filterByCircularity 원형 비율 필터 옵션
filterByColor 밝기 필터 옵션
filterByConvexity 볼록 비율 필터 옵션
filterByInertia 관성 비율 필터 옵션
minArea, maxArea min, max 범위 면적만 검출
minCircularity, maxCircularity min, max 범위 원형 비율만 검출
minConvexity, maxConvexity min, max 범위 볼록 비율만 검출
minIntertiaRatio, maxIntertiaRatio min, max 범위 관성 비율만 검출
minThreshold, maxThreshold BLOB 생성 임계값
thresholdstep maxThreshold를 넘지 않을 때까지 thresholdstep만큼 증가

 

6. 실행 속도 비교

아래 표는 위에서 설명한 5가지의 검출기에 대한 실행 속도를 time 모듈로 비교한 결과다.

Harris 0.009940862655639648
Shi-Tomasi 0.025163650512695312
GFTTDetector 0.019945621490478516
FAST 0.0009505748748779297
BLOB 0.02960824966430664

작업자의 환경에 따라 결과는 다르게 나타날 수 있지만, FAST 검출기가 10배 이상 빠른 처리를 하는 것으로 나타났다.

 

 

* 이 글에서는 배틀그라운드 무기 중 하나인 vector를 이미지로 활용합니다.

728x90
반응형
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 라이프코리아트위터 공유하기
  • shared
  • 카카오스토리 공유하기