코딩일지(2023-04-22)
해리스 코너 디텍터가 뭔지 알아보자!
해리스 코너 디텍터,, 너란녀석….
이미지 피처 추출에서 가장 처음 배운게 바로 이 해리스 코너 디텍러(Harris Corner Detector)다. 1988년에 해리스 반응(Harris Response)을 기반으로 이미지 내의 코너를 효과적으로 찾는 방법에 있어서 한 획을 그은 인물인 것 같다.
그의 아이디어는 생각보다 단순해서 컴퓨터에 있어서도 연산량이 적은 편이다. (물론 그만큼 성능은 떨어지긴 하지만 말이다 ㅋㅋ)
이름에서 드러나 있듯이, 코너는 이미지에서 모서리뿐만 아니라 눈에 띄는 구조적 특징을 나타낸다. 쉽게 말해서 이미지를 작게 블록으로 쪼갠 다음, 각 블록에서의 변화를 분석해서 어떤 물체가 있으면 이에 대한 눈에 띄는 지점들을 나타낸다고 볼 수 있다.
총 5가지 단계로 나눠서 생각해볼 수 있는데,
일단 기본적으로 1.이미지를 그레이스케일로 변환해준다. 나도 잘은 모르겠지만 그레이스케일로 변환해야만 색상정보를 무시하고 픽셀강도에 집중할 수 있어, 더 탐지가 잘된다나?ㅇㅇ
그 이후에 2.구조텐서 계산을 진행해준다. 기울기를 뽑아내기 위해 픽셀강도의 변화량을 측정하는데, 이때 소벨(Sobel)연산을 통해 계산된다고 한다. 이렇게 구한 기울기,즉 그래디언트를 가지고 구조텐서를 구해주게 된다.
구조텐서는 크게 세가지를 구하게 된다.
- x축 방향 기울기의 제곱
- y축 방향 기울기의 제곱
- x축과 y축 기울기의
이를 통해 이미지의 특정영역에서 기울기가 얼마나 변화하는지 분석할 수 있고, 이는 특징점 식별에 중요한 단서가 된다.
이를 기반으로 코너응답을 계산한다. 코너응답함수(Corner Response Function)를 써서 응답값을 구한다.(자세한 내용은 여기 링크로!)
위 식에서 det(M)은 lambda_1 * lambda_2라고 볼 수 있고,
trace(M)은 lambda_1 + lambda_2라고 볼 수 있다.
그리고 k는 하이퍼파라미터인데, 보통 0.04~0.06사이의 값을 넣어서 사용하는게 일반적이라고 한다.
마지막으로 코너를 검출한다.
코너 응답값이 특정 임계값을 넘는 픽셀을 코너로 간주한다. 추가적으로 지역 최대값(로컬 맥시마)만을 선택하여 중복된 코너를 제거하고, 가장 뚜렷한 코너만을 남깁니다.
코드 실습
아래 순서도를 기반으로 코드를 구현해보았다.
코드>
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 이미지 읽어오기
filename = './temp_image/checkboardroom.jpg'
img = cv2.imread(filename)
img2 = cv2.imread(filename)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# 해리스 코너 검출 파라미터 설정
block_size = 6 # 코너 검출을 위한 이웃 픽셀의 크기
ksize = 7 # Sobel 미분 커널의 크기
k = 0.05 # Harris 코너 검출기의 민감도 매개변수
threshold = 0.01 # 코너 검출 임계값
# 해리스 코너 검출 수행
gray = np.float32(gray)
dst = cv2.cornerHarris(gray, block_size, ksize, k)
# imagesc
plt.figure(figsize=(15, 5))
plt.imshow(dst)
plt.colorbar()
# display
plt.show()
결과>
위 코드를 기반으로 코너표시를 해주었다.
코드>
# 코너 표시를 위한 임계값 설정
img[dst>threshold*dst.max()]=[255,0,0]
plt.figure(figsize=(15, 5))
plt.subplot(121)
plt.imshow(img2)
plt.title('origin_img')
plt.subplot(122)
plt.imshow(img)
plt.title('dst_img')
plt.show()
결과>
이번에는 다른 예시를 구현해보았다. 우리의 시바견을 가지고 임계값에 따른 코너표시의 정도를 구분해보았다.
threshold = 0.01 * harris_corners.max()
인 경우:
코드>
import cv2
image = cv2.imread("./temp_image/siba.jpg", cv2.IMREAD_GRAYSCALE)
harris_corners = cv2.cornerHarris(image, blockSize=2, ksize=3, k=0.04)
threshold = 0.01 * harris_corners.max() # 코너 응답의 최대값을 기준으로 스레숄드 설정
corners = (harris_corners > threshold).astype(int) # 스레숄드 이상의 코너를 감지
import matplotlib.pyplot as plt
# 원본 이미지에 코너를 강조
corner_image = image.copy()
corner_image[corners == 1] = 255 # 코너 응답이 높은 부분을 강조
plt.imshow(corner_image, cmap='gray') # 회색조로 이미지 표시
plt.title("Detected Corners")
plt.show()
결과>
threshold = 0.001 * harris_corners.max()
인 경우:
import cv2
image = cv2.imread("./temp_image/siba.jpg", cv2.IMREAD_GRAYSCALE)
harris_corners = cv2.cornerHarris(image, blockSize=2, ksize=3, k=0.04)
threshold = 0.001 * harris_corners.max() # 코너 응답의 최대값을 기준으로 스레숄드 설정
corners = (harris_corners > threshold).astype(int) # 스레숄드 이상의 코너를 감지
import matplotlib.pyplot as plt
# 원본 이미지에 코너를 강조
corner_image = image.copy()
corner_image[corners == 1] = 255 # 코너 응답이 높은 부분을 강조
plt.imshow(corner_image, cmap='gray') # 회색조로 이미지 표시
plt.title("Detected Corners")
plt.show()
결과>
threshold = 0.0001 * harris_corners.max()
인 경우:
코드>
import cv2
image = cv2.imread("./temp_image/siba.jpg", cv2.IMREAD_GRAYSCALE)
harris_corners = cv2.cornerHarris(image, blockSize=2, ksize=3, k=0.04)
threshold = 0.0001 * harris_corners.max() # 코너 응답의 최대값을 기준으로 스레숄드 설정
corners = (harris_corners > threshold).astype(int) # 스레숄드 이상의 코너를 감지
import matplotlib.pyplot as plt
# 원본 이미지에 코너를 강조
corner_image = image.copy()
corner_image[corners == 1] = 255 # 코너 응답이 높은 부분을 강조
plt.imshow(corner_image, cmap='gray') # 회색조로 이미지 표시
plt.title("Detected Corners")
plt.show()
결과>
댓글남기기