식1 , 식2
설명 1
설명 2
원의 매개변수 방정식
허프 변환(Hough Transformation)
- 이미지에서 특정 모양( 주로 직선이나 원 )을 탐지하는데 사용되는 기법이다.
- 특징 검출( feature detection )에서 중요한 역할을 한다.
- 목적
- 이미지 내에서 직선 , 원 , 타원 등 특정 형태를 찾는데 사용함.
- 직선 검출 ( 도로 차선 탐지 )
- 원 검출 ( 동공 검출 , 동전 인식 )
- 일반 곡선 검출 ( 특정 형상의 곡선 탐지 )
- 장점
- 단점
- 매개변수가 많아질수록 누적배열이 많아져서 계산 비용 증가
- 고해상도 이미지의 경우는 메모리 사용이 크다.
- 매개변수 이산화 수준에 따라서 검출 정확도에 영향을 받음
- 활용
- 직선 검출 원리
- 1. 직선은 일반적으로 데카르트 좌표계로 표현되나, 기울기가 수직인 경우에는 무한대가 될수 있으니 극좌표계를 사용한다. ( 식 1 , 식 2 , 설명 1 참고 )
- 2. 이미지 공간에서 직선을 표현하면, 모든 픽셀은 ( x, y )좌표를 가지며, 각 픽셀에서 모든 가능한 직선을 계산하여 허프 공간에 매핑한다. ( 설명 2 참고 )
- 허프 공간에 매핑시에 동일한 직선을 공유하면, 동일한 ( r , theta )값을 가지니 이 값들이 누적된다.
즉, 누적된 값이 클수록, 해당 직선을 구성하는 픽셀이 많다는 뜻이다.
- 3. 위의 과정을 통해 r과 theta를 이산화 한 누적 배열accumulator이 생성된다.
- 누적 배열에서 높은 값은 이미지 내에서 직선이 존재할 가능성이 높은 것이다.
- 원 검출 원리
- 1. 원의 방정식을 사용하여 허프 공간으로 매피 할것이다.
- 1-1. 이를 위해서 ( a , b , r )이라는 3가지 매개변수를 허프 공간으로 매핑한다.
- 각 edge 픽셀에서 r값에 따라 가는한 모든 ( a , b )를 계산한다.
- 누적 배열은 4차원일것이며, 누적값이 큰 지점은 원의 중심과 반지름을 나타낸다.
- 알고리즘 단계
- 1. canny , sobel 등을 이용하여 엣지 검출을 한다.
- 2. 허프 공간을 생성한다.
- 3. 누적 배열을 업데이트하며 채운다.
- 4. 최대값 탐색.
- 5. 이미지에 시각화.
cv2.HoughLines( src , rho , theta , threshold , lines , srn=0 , stn=0 , min_theta , max_theta )
- src : 입력 이미지. 1차원
- rho: 거리 측정 해상도이며 0~1이다.
- 값이 작아질수록 해상도가 높아지며 계산량 증가
- theta: 각도 , 라디안 단위
- threshold : 직선으로 판단할 최소한의 동일 개수
- 작을수록 정확도는 감소하나, 검출 개수는 증가
- 클수록 정확도는 증가하나 검출 개수는 감소
import numpy as np
import cv2
# 원본을 그냥 2번 읽음
origin = cv2.imread( 'warehouse.jpg' )
img = cv2.imread( 'warehouse.jpg' , cv2.IMREAD_GRAYSCALE )
# canny를 이용하여 엣지 검출
edges = cv2.Canny( img , 220 , 240 )
# 하프선 검출
lines = cv2.HoughLines( edges , 1 , np.pi/180 , 130 )
print( lines.shape )
print(lines[ 0 ])
print(lines)
# 원본에 그리기
for line in lines:
rho , theta = line[ 0 ] # 각도와 r값을 알고 있는 경우 x,y좌표를 구할수있다.
a , b = np.cos( theta ) , np.sin( theta ) # x y 좌표를 구한다.
x0 , y0 = a*rho , b*rho
cv2.circle( origin , ( int(abs( x0 )) , int(abs( y0 )) ), 3 , ( 0 , 0 , 255 ) , -1 )
x1 , y1 = int( x0 + 1000 * ( -b ) ) , int( y0 + 1000 * a )
x2 , y2 = int( x0 - 1000 * ( -b ) ) , int( y0 - 1000 * a )
cv2.line( origin , ( x1 , y1 ) , ( x2 , y2 ) , ( 0 , 255 , 0 ) , 1 )
cv2.imshow('hough line', origin)
cv2.waitKey()
cv2.destroyAllWindows()