Python/파이썬 OpenCV 공부

[파이썬 OpenCV] 영상의 코너 검출 - Harris, GFTT, FAST - cv2.FastFeatureDetector_create, cv2.goodFeaturesToTrack

AI 꿈나무 2020. 10. 15. 21:42
반응형

1. 코너 검출

 코너는 영상안에서 그림이 나타날 때 객체가 뾰족하게 튀어나온 부분입니다.

 코너를 검출하는 이유는 코너점들이 영상에서 고유한 특징을 갖고 있어서 변별력 있게 잘 검출할 수 있는 특징입니다.

 

 이와 반대로 평탄한 영역(flat)과 에지(edge) 영역은 고유한 위치를 찾기 어렵습니다.

 

원본사진
평탄한 영역
에지

 

코너

 

 평탄한 영역은 하늘에서 추출한 부분 영상입니다.

 이 부분 영상이 원본 영상에서 어느 부분인지 명확하지 않습니다.

 모호한 부분이 많아 변별력이 떨어지게 됩니다.

 영상의 특징을 설명하는 데 적합하지 않습니다.

 

 에지는 바다와 하늘이 만나는 부분입니다.

 원본 영상에서 x좌표가 명확하게 어느 부분인지 정확하게 찾기가 어렵습니다.

 따라서 고유성과 변별성이 떨어집니다.

 

 코너는 원본 영상에서 코너 영상과 동일한 부분을 딱 한군데가 있으며 눈으로 찾아봐도 알 수 있습니다.

 이처럼 로컬한 특징을 갖고있어서 변별성이 있고 고유성이 있습니다.

 코너점을 찾아서 점들의 특징을 이용하여 두 개의 영상을 비교하거나 차이점을 찾거나 매칭을 하는 용도로 쓰입니다.

 

2. 다양한 코너 검출 방법

 대표적으로 많이 이용하는 3가지 코너 검출 방법을 알아보겠습니다.

 

(1) 해리스 - Harris

 1980년대에 나온 코너 검출 방법으로 상당히 유명합니다.

 유명한 이유는 성능이 좋기보다 코너점을 검출하는 이론적 토대를 잘 만들어서 유명합니다.

 Harris 함수이 반환한 값에 임계점을 설정해서 사용합니다. (후처리 필요)

 OpenCV에서는 해리스 코너 검출 함수를 제공하지만 다른 방법을 이용하는 것이 더 좋습니다.

 

[특징]

- 영상 내부 작은 영역이 모든 방향에 대해 변화가 큰 경우 코너로 규정

- 코너 응답 함수 R을 반환 -> R(x,y)가 충분히 크면 코너로 구분

- cv2.cornerHarris() 함수 사용

 

(2) 추적하기 좋은 특징 - Good Features to Track

 해리스 코너 검출을 업그레이드 방법입니다.

 해리스 코너 검출은 코너 응답 함수 R(입력 영상과 동일한 실수형 형태)를 반환합니다.

 R 행렬 요소의 크기가 충분히 크면 코너로 판단하는 근거로 삼습니다.

 하지만 점이 붙어 있을수도 있고 로컬 맥시멀이 아닌 경우도 검출할 수 있습니다.

 추적하지 좋은 특징 방법은 비최대 억제 수행으로 로컬맥시말을 검출합니다.

 또한 반환값은 코너점을 반환시켜줘서 사용하기가 편합니다.

 

[특징]

- 해리스 코너 검출 방법을 기반으로 향상된 방법

- 비최대 억제 수행

- 코너 품질 함수를 정의 -> 가장 값이 큰 순서대로 정렬하여 반환

- cv2.goodFeaturesToTrack 함수 사용

 

(3) FAST - Features from Accelerated Segment Test

 기존의 방법들과 접근 방법이 다르게 코너를 검출합니다.

 특정 픽셀 주변 16개 픽셀 값들을 조사해서 그 픽셀값이 가운데 픽셀보다 충분히 어둡거나 충분히 밝은 픽셀이 9개 이상 나타나면 코너라고 판단합니다.

 

 

 위 그림에서 가운데에 p점이 있고 주변 픽셀을 1번부터 16번까지 번호를 지정합니다.

 p점보다 밝거나 어두운 것들이 9개 이상이면 코너로 판단합니다.

 가장 효율적인 코너 검출 방법은 FAST 입니다.

 

[특징]

- 주변 16개 픽셀 값 크기를 분석

- 기준 픽셀(p)보다 충분히 밝거나 또는 충분히 어두운 픽셀이 n개 연속으로 나타나면 코너로 인식(n은 보통 9)

- 해리스, GFTT 방법보다 매우 빠르게 동작

 

3. 해리스 코너 응답 함수 계산 - cv2.cornerHarris

cv2.cornerHarris(src, blockSize, ksize, k, dst=None, borderType=None) -> dst

• src: 입력 단일채널 8비트 또는 실수형 영상

• blockSize: 코너 응답 함수 계산에서 고려할 이웃 픽셀 크기. 보통 2~5.

• ksize: (미분을 위한) 소벨 연산자를 위한 커널 크기. 보통 3.

• k: 해리스 코너 검출 상수 (보통 0.04~0.06)

• dst: 해리스 코너 응답 계수. src와 같은 크기의 행렬(numpy.ndarray). dtype=numpy.float32.

• borderType: 가장자리 픽셀 확장 방식. 기본값은 cv2.BORDER_DEFAULT.

 blockSize : 보통 3정도 입력합니다

 k : 논문에서 나온 상수이며 0.04~0.06을 입력합니다.

 나머지 값은 디폴트로 지정해도 됩니다.

 

 dst : 결과값은 코너 응답 함수라는 플로트 타입 행렬을 반환합니다. 이 값에서 임계점을 지정해서 코너를 검출해야 합니다.

 

4. 추적하기 좋은 특징 코너 검출 - cv2.goodFeaturesToTrack()

 해리스 코너 검출 방법보다 인자가 더 많습니다.

 

cv2.goodFeaturesToTrack(image, maxCorners, qualityLevel, minDistance, corners=None, mask=None, blockSize=None, useHarrisDetector=None, k=None) -> corners

• image: 8비트 또는 32비트 실수, 단일채널 영상

• maxCorners: 최대 코너 개수. maxCorners <=0 이면 무제한.

• qualityLevel: 코너점 결정을 위한 값. 보통 0.01 ~ 0.1.

• minDistance: 코너점 사이의 최소 거리

• corners: 검출된 코너점 좌표. numpy.ndarray. shape=(N, 1, 2). dtype=numpy.float32.

• mask: 마스크 영상

• blockSize: 코너 검출을 위한 블록 크기. 기본값은 3.

• useHarrisDetector: 해리스 코너 방법 사용 여부. 기본값은 False.

• k: 해리스 코너 검출 시 사용할 k 값

  mindistancd는 코너점이 너무 근접하게 나타나면 하나를 버립니다. 10으로 설정하면 10픽셀 근방 점들중 가장 큰거를 선택하고 나머지는 버립니다.

 

 주의할 점은 반환값인 corners입니다.

 3차원 실수 행렬(N,1,2)로 반환하며 N으 코너점 검출 갯수입니다.

 x 좌표는 [i, 0, 0], y좌표는 [i, 0, 1] 입니다.

 실수로 저장되므로 int로 변환하여 사용해야 합니다.

 

5. FAST 코너 검출 - cv2.FastFeatureDetector_create()

 FastFeatureDetector 클래스 형태로 구현합니다.

 cv2.FastFeatureDetector_create() 함수로 클래스 객체를 만들고 .detect() 함수로 코너점을 검출합니다.

 

cv2.FastFeatureDetector_create(, threshold=None, nonmaxSuppression=None, type=None) -> retval

• threshold: 중심 픽셀 값과 주변 픽셀 값과의 차이 임계값. 기본값은 10. 30~60 적절

• nonmaxSuppression: 비최대 억제 수행 여부. 기본값은 True.

• type: 코너 검출 방법. 기본값은 cv2.FAST_FEATURE_DETECTOR_TYPE_9_16.

• retval: FastFeatureDetector 객체

 threshold : 임계값을 50으로 설정했으면 p점보다 50더 밝거나 어두우면 코너로 판단합니다. 기본값은 10이지마 30~60 정도 설정하는 것이 좋습니다.

 

 type : 9_16은 16개 픽셀에서 9개가 밝거나 어두우면 코너로 검출하겠다는 의미입니다.

 

cv2.FastFeatureDetector.detect(image) -> keypoints

• image: (입력) 그레이스케일 영상

• keypoints: (출력) 검출된 코너점 정보. cv2.KeyPoint 객체를 담은 리스트. cv2.KeyPoint의 pt 멤버를 이용하여 코너 좌표 추출. pt[0]은 x좌표, pt[1]은 y좌표.

 keypoints는 cv2.KeyPoint 객체를 담은 리스트를 반환합니다.

 cv2.KeyPoint 객체 내부에 pt멤버는 실수형 코너 좌표를 갖고 있습니다.

 pt에는 x멤버변수, y멤버변수가 있습니다.

 detect로 코너를 검출하면 keypoint에서 pt 멤버에 있는 좌표 정보를 받아야합니다.

 

6. GFTT와 FAST 코너 검출 예제

예제 코드 출처 :  황선규 박사님 github홈페이지 sunkyoo.github.io/opencv4cvml/

 

src = cv2.imread('building.jpg', cv2.IMREAD_GRAYSCALE)

if src is None:
    print('Image load faile!')
    sys.exit()
    
# 좋은 특징점 검출 방법
corners = cv2.goodFeaturesToTrack(src, 400, 0.01, 10)

dst1 = cv2.cvtColot(src, cv2.COLOR_GRAY2BGR)

if corners is not None:
    for i in range(corners.shape[0]): # 코너 갯수만큼 반복문
        pt = (int(corners[i, 0, 0]), int(corners[i, 0, 1]))) # x, y 좌표 받아오기
        cv2.circle(dst1, pt, 5, (0, 0, 255), 2) # 받아온 위치에 원
        

# Fast 코너 검출
fast = cv2.FastFeatureDetector_create(60) # 임계값 60 지정
keypoints = fast.detect(src) # Keypoint 객체를 리스트로 받음

dst2 = cv2.cvtColor(src, cv2.COLOR_GRAY2BGR)

for kp in keypoints:
    pt = (int(kp.pt[0]), int(kp.pt[1])) # kp안에 pt좌표가 있음
    cv2.circle(dst2, pt, 5, (0, 0, 255), 2)

cv2.imshow('src', src)
cv2.imshow('dst1', dst1)
cv2.imshow('dst2', dst2)
cv2.waitKey()

cv2.destroyAllWindows()

 

원본 영상

 

추적하기 좋은 특징점 검출 방법

 

FAST 방법

 

7. 코너 검출 방법 성능 비교

 FAST 방법의 반복 검출률이 대체로 높습니다. 하지만 FAST 방법은 노이즈에 민감합니다.

 영상에 변형이 있더라도 FAST는 코너를 잘 찾지만 입력 영상에 노이즈가 들어가게 되면 검출률이 떨어집니다.

 그렇다하더라도 속도가 월등히 빨라 가우시안 블러를 적용해서 사용하는 경우도 많습니다.

 

 


OpenCV 튜토리얼과 황선규 박사님의 'OpenCV 4로 배우는 컴퓨터 비전과 머신 러닝' 을 공부하면서 정리해 보았습니다.

docs.opencv.org/4.3.0/db/d27/tutorial_py_table_of_contents_feature2d.html

 

반응형