OpenCV Review 08

2400·2025년 3월 17일
post-thumbnail

Harris 코너 검출 알고리즘 구현 설명

Harris 코너 검출 알고리즘은 이미지에서 코너(corner)를 찾기 위한 방법이다.

컴퓨터 비전에서 말하는 코너(corner)는 이미지에서 두 개 이상의 방향으로 급격한 강도(intensity) 변화가 있는 지점을 의미한다.

  • 기하학적 코너: 객체의 윤곽선이 급격하게 방향을 바꾸는 지점으로, 일반적으로 우리가 일상에서 생각하는 "모서리"와 유사
  • 그래디언트 관점의 코너: 두 개 이상의 서로 다른 방향에서 픽셀 값이 크게 변하는 지점

1. 초기 설정 및 테스트 이미지 생성

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자 모양의 객체를 포함하고 있으며, 코너 검출에 사용된다.

2. 그래디언트 계산을 위한 필터 정의

ux = np.array([[-1,0,1]])                # x 방향 미분 필터
uy = np.array([[-1,0,1]]).transpose()    # y 방향 미분 필터

이미지의 x방향과 y방향 그래디언트를 계산하기 위한 소벨 필터를 정의합니다. 이 필터는 각 방향의 변화율을 측정한다.

3. 가우시안 가중치 필터 생성

k = cv.getGaussianKernel(3,1)           # 3×3 크기, 표준편차 1인 1D 가우시안 커널
g = np.outer(k, k.transpose())          # 1D 커널을 2D로 확장

가우시안 필터는 주변 픽셀의 기여도에 가중치를 부여하는 데 사용된다. np.outer()는 두 벡터의 외적을 계산해 2D 가우시안 커널을 만든다.

4. 이미지 그래디언트 계산

dy = cv.filter2D(img, cv.CV_32F, uy)    # y 방향 그래디언트
dx = cv.filter2D(img, cv.CV_32F, ux)    # x 방향 그래디언트

정의된 필터를 사용하여 이미지의 x방향과 y방향 그래디언트를 계산한다. filter2D 함수는 이미지에 커널을 적용한 컨볼루션 결과를 반환한다.

5. 구조 텐서(Structure Tensor) 요소 계산

dyy = dy * dy    # y 방향 그래디언트 제곱
dxx = dx * dx    # x 방향 그래디언트 제곱
dyx = dx * dy    # x와 y 방향 그래디언트 곱

구조 텐서의 요소들을 계산한다. 이 텐서는 각 픽셀 주변의 그래디언트 방향과 크기에 대한 정보를 담고 있다.

6. 가우시안 스무딩 적용

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에 가우시안 스무딩 적용

계산된 구조 텐서 요소들에 가우시안 스무딩을 적용한다. 이는 지역적 변화를 더 견고하게 측정하기 위한 것이다.

7. Harris 응답 계산

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)를 곱한 값
  • 행렬식에서 트레이스 제곱을 감산하여 코너에서는 큰 양수값, 엣지에서는 음수값, 평탄한 영역에서는 작은 값을 갖게 된다.

8. 코너 판별 및 마킹

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로 변경

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() 함수를 사용하면 더 효율적으로 코너를 검출할 수 있다.

profile
시즌 2의 공부기록 - Artificial Intelligence & AeroSpace

0개의 댓글