가장자리 픽셀이 1로 표시되고 가장자리가 아닌 픽셀이 0으로 표시되는 이진 이미지가 주어지면 허프 변환의 목표는 이 이미지 내의 선을 감지하는 것이다.
데카르트 좌표계의 선을 방정식 y = mx + b로 표현된다. 여기서 m은 기울기이고 b는 y 절편이다. 하지만 이 표현은 수직선이기 때문에 대안으로 극좌표계를 사용한다.
xcosθ+ysinθ=p
여기서 p는 원점에서 가장 가까운 점까지의 거리이고, 각도는 x축과 최단 거리 선 사이의 각도이다.
이미지의 각 가장자리 점(x,y)에 대해 해당 점을 통과하는 모든 선을 나타내는 (p, 각도) 공간이 곡선이 있다. 허프 변환에서는 p 및 각도를 축으로 사용하여 일반적으로 누산기라고 하는 이 매개변수 공간에 히스토그램을 구성한다.
각 가장자리 픽셀(x,y)에 대해 값을 방정식 xcosθ+ysinθ=ρ에 연결한 다음 각 (ρ,θ) 쌍에 대해 누산기의 값을 증가시킵니다. 기본적으로 각 가장자리 픽셀은 매개변수 공간의 잠재적인 선에 대해 "투표"합니다.
각 가장자리 픽셀이 투표된 후 누산기의 최고점을 이미지에서 감지된 라인의 매개변수를 나타낸다. 피크의 위치의 값은 해상도, 임계값 및 원래 가장자리 감지와 같은 다양한 요소에 따라 달라진다.
import cv2
import numpy as np
img = cv2.imread('3GkY2CQ.jpg', cv2.IMREAD_COLOR)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray,(5,5),0)
circles = cv2.HoughCircles(blur, cv2.HOUGH_GRADIENT, 1, 20, param1=50, param2=30, minRadius=0, maxRadius=0)
if circles is not None:
circles = np.uint16(np.around(circles))
for i in circles[0,:]:
cv2.circle(img,(i[0],i[1]),i[2],(0,255,0),2)
cv2.circle(img,(i[0],i[1]),2,(0,0,255),3)
cv2.imwrite('detected_circle.jpg', img)
가우시안 블러를 적용하여 노이즈를 줄이는 데, 그래도 원이 잡히지 않으면 가우시안 블러를 여러번 적용해보자(나는 보통 (7,7), (5,5), (3,3)으로 적용해본다).
그래도 원이 잡히지 않으면 캐니 디텍터를 (50,150)으로 준다.
circles = cv2.HoughCircles(blur, cv2.HOUGH_GRADIENT, a = 1, b = 20, param1=50, param2=30, minRadius=0, maxRadius=0)
a는 1에서 어떤 값으로 바꿔도 생각보다 별 영향을 주지 않는다.
b는 원 사이의 픽셀값을 말하는데, 이 값에 따라서 찾아지는 원의 개수에 영향을 받는다.
param1보다 param2가 더 중요한 영향을 미치는데, 이 값은 정말 아무 숫자를 계속 넣어보면서 원이 잘 찾아지는지 확인해야 한다.
minRadius와 maxRadius에는
axis와 찾으려는 원의 크기를 x축과 y축을 보면서 파악하여 최소 원의 반지름과 최대 원의 반지름의 픽셀값을 적어 넣으면 된다.