Hough变换是一种检测、定位直线和解析曲线的有效方法。是把二值图变换到Hough参数空间,在参数空间用极值点的检测来完成目标的检测和分割 。
原理
首先,我们可知对一直角坐标系中的直线其方程可写为:
ρ
=
x
s
i
n
θ
+
y
c
o
s
θ
\rho=xsin\theta+ycos\theta
ρ=xsinθ+ycosθ,即参数
ρ
\rho
ρ和
θ
\theta
θ可确定一条直线。
其中
ρ
\rho
ρ是原点到直线的距离,
θ
\theta
θ是该直线的法线与X轴的夹角。
那么对于X-Y平面内的点(x0,y0)可以转换为:
ρ
=
x
0
s
i
n
θ
+
y
0
c
o
s
θ
=
A
s
i
n
(
α
+
θ
)
\rho=x_0sin\theta+y_0cos\theta=Asin(\alpha+\theta)
ρ=x0sinθ+y0cosθ=Asin(α+θ),其中
α
=
a
r
c
t
a
n
(
x
0
/
y
0
)
;
A
=
x
0
2
+
y
0
2
\alpha=arctan(x_0/y_0);A=\sqrt {x_0^2+y_0^2}
α=arctan(x0/y0);A=x02+y02。这在
ρ
\rho
ρ-
θ
\theta
θ平面中是一条正弦曲线,而初始角
α
\alpha
α和振幅
A
A
A随x0和y0的值而变。
如果将X-Y平面内一条直线上的点都变换到
ρ
\rho
ρ-
θ
\theta
θ平面中,所有的正弦曲线都将经(
ρ
0
\rho_0
ρ0,
θ
0
\theta_0
θ0),所有正弦曲线在
ρ
\rho
ρ-
θ
\theta
θ平面中的其他位置都不相交。
也就是说,原直线上的点经转换后经过点(
ρ
0
\rho_0
ρ0,
θ
0
\theta_0
θ0)的次数为无穷次,其他位置均为一次。
因此,为检测图像中的直线,我们只需建立二维数组A(
ρ
\rho
ρ,
θ
\theta
θ),对二值图像上的目标点以
θ
\theta
θ不断变化算出
ρ
\rho
ρ,使得A中的对应元素累加,即A(
ρ
\rho
ρ,
θ
\theta
θ)+=1,最后找到数组中最大值的点就是二值图中最长直线的参数。
代码
def Hough(img,origin,delta=0):
res=origin.copy()
thetas=np.deg2rad(np.arange(0.0,180.0,1))
row,col=img.shape
rhomax=int(round(np.sqrt(row*row+col*col)))
#因为ρ会存在负值,所以要先右移,后面减去即可
A=np.zeros((2*rhomax,len(thetas)),np.int32)
for x in range(row):
for y in range(col):
if img[x,y]>0:
for i in range(len(thetas)):
rho=int(round(x*np.cos(thetas[i])+y*np.sin(thetas[i])))
rho+=rhomax
A[rho,i]+=1
#数组中最大值索引
(maxr,maxt)= np.unravel_index(A.argmax(),A.shape)
theta=thetas[maxt]
#标记出最长直线
for x in range(row):
for y in range(col):
if img[x,y]>0:
rho=int(x*np.cos(theta)+y*np.sin(theta))
rho+=rhomax
if abs(rho-maxr)<=delta:
res[x,y]=[0,0,255]
return maxr-rhomax,theta,res