Harris 코너 검출 알고리즘은 이미지에서 코너(corner)를 찾기 위한 방법이다.
컴퓨터 비전에서 말하는 코너(corner)는 이미지에서 두 개 이상의 방향으로 급격한 강도(intensity) 변화가 있는 지점을 의미한다.
import cv2 as cv
import numpy as np
img = np.array([[0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0],
[0,0,0,1,0,0,0,0,0,0],
[0,0,0,1,1,1,0,0,0,0],
[0,0,0,1,1,1,1,0,0,0],
[0,0,0,1,1,1,1,1,0,0],
[0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0]
], dtype= np.float32)
간단한 10×10 픽셀의 이진 이미지를 생성합니다. 이미지는 L자 모양의 객체를 포함하고 있으며, 코너 검출에 사용된다.
ux = np.array([[-1,0,1]]) # x 방향 미분 필터
uy = np.array([[-1,0,1]]).transpose() # y 방향 미분 필터
이미지의 x방향과 y방향 그래디언트를 계산하기 위한 소벨 필터를 정의합니다. 이 필터는 각 방향의 변화율을 측정한다.
k = cv.getGaussianKernel(3,1) # 3×3 크기, 표준편차 1인 1D 가우시안 커널
g = np.outer(k, k.transpose()) # 1D 커널을 2D로 확장
가우시안 필터는 주변 픽셀의 기여도에 가중치를 부여하는 데 사용된다. np.outer()는 두 벡터의 외적을 계산해 2D 가우시안 커널을 만든다.
dy = cv.filter2D(img, cv.CV_32F, uy) # y 방향 그래디언트
dx = cv.filter2D(img, cv.CV_32F, ux) # x 방향 그래디언트
정의된 필터를 사용하여 이미지의 x방향과 y방향 그래디언트를 계산한다. filter2D 함수는 이미지에 커널을 적용한 컨볼루션 결과를 반환한다.
dyy = dy * dy # y 방향 그래디언트 제곱
dxx = dx * dx # x 방향 그래디언트 제곱
dyx = dx * dy # x와 y 방향 그래디언트 곱
구조 텐서의 요소들을 계산한다. 이 텐서는 각 픽셀 주변의 그래디언트 방향과 크기에 대한 정보를 담고 있다.
gdyy = cv.filter2D(dyy, cv.CV_32F, g) # dyy에 가우시안 스무딩 적용
gdxx = cv.filter2D(dxx, cv.CV_32F, g) # dxx에 가우시안 스무딩 적용
gdyx = cv.filter2D(dyx, cv.CV_32F, g) # dyx에 가우시안 스무딩 적용
계산된 구조 텐서 요소들에 가우시안 스무딩을 적용한다. 이는 지역적 변화를 더 견고하게 측정하기 위한 것이다.
C = (gdyy * gdxx - gdyx * gdyx) - 0.04 * (gdyy + gdxx) * (gdyy + gdxx)
Harris 코너 응답 함수
(gdyy * gdxx - gdyx * gdyx): 구조 텐서의 행렬식(determinant)0.04 * (gdyy + gdxx) * (gdyy + gdxx): 구조 텐서의 트레이스(trace) 제곱에 상수 k(0.04)를 곱한 값for j in range(1, C.shape[0]-1):
for i in range(1, C.shape[1]-1):
if C[j, i] > 0.1 and sum(sum(C[j,i] > C[j-1 : j+2, i-1 : i+2]))==8:
img[j,i] = 9
각 픽셀에 대해:
1. Harris 응답 값이 임계값(0.1)보다 큰지 확인
2. 해당 픽셀의 응답 값이 주변 8개 픽셀보다 모두 큰지 확인(국소 최대값)
3. 두 조건이 모두 충족되면 해당 픽셀을 코너로 판단하고 값을 9로 변경
np.set_printoptions(precision = 2)
print(dy) # y 방향 그래디언트
print(dx) # x 방향 그래디언트
print(dyy) # y 방향 그래디언트 제곱
print(dxx) # x 방향 그래디언트 제곱
print(dyx) # x와 y 방향 그래디언트 곱
print(gdyy) # 스무딩된 dyy
print(gdxx) # 스무딩된 dxx
print(gdyx) # 스무딩된 dyx
print(C) # Harris 응답 값
print(img) # 코너가 표시된 최종 이미지
실제 응용에서는 OpenCV의 cv.cornerHarris() 함수를 사용하면 더 효율적으로 코너를 검출할 수 있다.