霍夫变换

霍夫变换是一种在图像中寻找直线、圆形以及其他简单形状的方法。它采用投票的方式来获取当前图像内的形状集合。

一:霍夫直线变换

1、霍夫变换原理
(1)笛卡尔坐标系:
霍夫变换_第1张图片

(2)霍夫坐标系
霍夫变换_第2张图片
说明:如上图所示,在笛卡尔坐标系中,直线y=k0*x+b0对应霍夫坐标系中的点(k0,b0),即笛卡尔坐标系的斜率和截距与霍夫坐标系中的点对应。

A:笛卡尔空间内一条直线确定霍夫空间内一个点
B:霍夫空间内的一个点确定笛卡尔空间内的一条直线

通过变换可得:

A:笛卡尔空间内的点(x0,y0)映射到霍夫空间,就是直线b=-x0*k+y0
B:霍夫空间内的直线b=-k*x0+y0映射到笛卡尔空间,就是点(x0,y0)

进一步可以推出:

	在笛卡尔空间内,有N个点能够连接成一条直线y=k1*x+b1,那么在霍夫空间内就会有N条直线穿
过对应的点(k1,b1),或者反过来说,如果在霍夫空间中,有越多的直线穿过点	(k1,b1),就说明在笛卡尔空间内有越多的点位于斜率为k1,截距为b1的直线
y=k1*x+b1上。(有点绕,需要自己仔细理解)

于是就可以得出我们今天所要说的:在霍夫空间内,经过一个点的直线越多,说明其在笛卡尔空间内映射的直线是由越多的点所构成(穿过)的。我们知道,两点构成一条直线,但有些点会因为错误计算而产生,由它所构成的直线实际是不存在的,我们要极力避免这种情况,因此在计算中用更多的点构造一条直线来提高直线的可靠度。因此,霍夫变换选直线的思路就是选有尽可能多的直线交汇的点。

当然,在笛卡尔空间中,可能存在斜率为无穷的直线(竖直的线),此时截距无法取值,因此不能与霍夫空间对应,此时就需要采用极坐标。(同笛卡尔坐标与霍夫坐标的映射关系相似,在此不作过多介绍)

2、HoughLines函数

lines=cv2.HoughLines(image, rho, theta, threshold)
image:输入图片,必须为8位单通道二值图像。
rho:以像素为单位的距离r的精度,一般情况下,使用的精度是1.
theta:角度的精度,一般情况下,使用的精度是Π/180,表示要搜索的所有可能角度
threshold:阈值,该值越小,判定出的直线就越多,(由上面理论可知,当少量的点穿过该直线
时,若我们都认为该直线存在,这样就会判定出很多直线,但这其中很大一部分直线实际是存在的)
lines:lines中的每个元素都是一对浮点数,表示检测到的直线的参数,即(距离,角度),
是numpy.ndarray类型

注:cv2.HoughLines()检测到的是图像中的直线而不是线段,因此是没有端点的,通过它绘制出来的直线是穿过整幅图像的

3、HoughLinesP函数

概率霍夫变换对基本霍夫变换算法做了一些修正,是霍夫变换算法的优化,它没有考虑所有的点,相反,它只需要一个足以进行线性检测的随机点子集即可。同时,它还对选取直线的方法做了两点改进。
(1):所接受直线的最小长度。如果有超过阈值个数的像素点构成一条直线,但这条直线很短,那么不接受该直线作为判断结果。而认为该直线仅是图像中若干个像素点恰好随机构成了一种算法上的直线关系而已。
(2):接受直线时允许的最大像素点间距,如果超过阈值点个数的像素点构成一条直线,但这组像素点之间的距离都很远,就不会接受该直线作为判断结果。

lines=cv2.HoughLinesP(image, rho, theta, threshold, minLineLength=None, maxLineGap=None)
image:输入图像,必须为8位单通道二值图像。
rho:以像素为单位的距离r的精度,一般情况下,使用的精度是1.
theta:角度的精度,一般情况下,使用的精度是Π/180,表示要搜索的所有可能角度
threshold:阈值,该值越小,判定出的直线就越多(同HoughLines函数)
minLineLength:用来控制“接受直线的最小长度”的值,默认为0
maxLineGap:控制接受共线线段之间的最小间隔,即在一条直线上两点的最大间隔,如果两点间的间隔超过了该参数,就认为该两点不在一条直线上。默认为0.
lines:由numpy.ndarray类型的元素构成,其中每个元素都是一对浮点数,表示检测到的直线的参数,即(距离,角度)

##########如下所示########

import cv2
import numpy as np
import matplotlib.pyplot as plt
img=cv2.imread(r"img/19.jpg",-1)

gary=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
edges=cv2.Canny(gary,50,150,apertureSize=3)

orgb_1=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
orgb_2=orgb_1.copy()
oshow=orgb_1.copy()
lines_1=cv2.HoughLines(edges,1,np.pi/180,140)
lines_2=cv2.HoughLinesP(edges,1,np.pi/180,1,minLineLength=100,maxLineGap=10)
####注意下面cv2.HoughLines的绘图,它是在极坐标中得到的
for line in lines_1:
    rho,theta=line[0]
    a=np.cos(theta)
    b=np.sin(theta)
    x0=a*rho
    y0=b*rho
    x1=int(x0+1000*(-b))
    y1=int(y0+1000*(a))
    x2=int(x0-1000*(-b))
    y2=int(y0-1000*(a))
    cv2.line(orgb_1,(x1,y1),(x2,y2),(255,0,0),5)

for line in lines_2:
    x1,y1,x2,y2=line[0]
    cv2.line(orgb_2,(x1,y1),(x2,y2),(255,0,0),5)

plt.subplot(221)
plt.imshow(oshow)
plt.subplot(222)
plt.imshow(edges)
plt.subplot(223)
plt.imshow(orgb_1)
plt.subplot(224)
plt.imshow(orgb_2)
plt.show()

霍夫变换_第3张图片

二:霍夫圆环变换

霍夫圆变换检测图像中的圆与使用霍夫直线变换检测直线的原理类似,在霍夫变换中,需要考虑圆半径和圆心(x,y)三个参数,在opencv中采用的是两轮筛选,第一轮找出可能的圆心位置,第二轮筛选半径大小。

circles=cv2.HoughCircles(image, method, dp, minDist, param1=None, param2=None, minRadius=None, maxRadius=None)
image:输入图像,即原图像,类型为8位单通道灰度图像
method:检测方法,目前HOUGH_GRADIENT是唯一可用的参数,代表霍夫圆检测中两轮检测所使用的方法,
dp:累计器分辨率,用来指定图像分辨率与圆心累加器分辨率的比例。如dp=1,则输入图像和累加器具有相同分辨率。
minDist:圆心间的最小距离,该值被作为阈值使用,若存在多个圆心间距小于该值,则仅有一个会被检测出来。
 param1:默认100,对应Canny边缘检测器的高阈值(低阈值为高阈值的1/2)。
 param2:默认100,圆心位置必须收到的投票,只有在第一轮中投票数高于该值,才会进入第二轮。
 minRadius:默认为0,此时该参数不起作用。圆的最小半径,小于该值的圆不会被检测出来
 maxRadius:默认为0,此时该参数不起作用。圆的最大半径,大于该值的圆不会被检测出来
 circles:返回值,由圆心坐标和半径构成的numpy.ndarray。

注:在调用该函数之前,要对源图像做平滑操作,以减小图像中的噪声,避免发生误判。

import cv2
import numpy as np
import matplotlib.pyplot as plt
img=cv2.imread(r"img/18.jpg",0)
img0=cv2.imread(r"img/18.jpg",-1)
o=cv2.cvtColor(img0,cv2.COLOR_BGR2RGB)
oshow=o.copy()
img=cv2.medianBlur(img,5)
circles=cv2.HoughCircles(img,cv2.HOUGH_GRADIENT,1,200,param1=80,param2=35,minRadius=100,maxRadius=200)
circles=np.uint16(np.around(circles))
for i in circles[0,:]:
    cv2.circle(o,(i[0],i[1]),i[2],(255,0,0),12)
    cv2.circle(o,(i[0],i[1]),2,(255,0,0),12)

plt.subplot(141)
plt.imshow(oshow)
plt.title("origin_img")
plt.axis("off")
plt.subplot(142)
plt.imshow(img,cmap="gray")
plt.title("medi_img")
plt.axis("off")
plt.subplot(143)
plt.imshow(o)
plt.title("result")
plt.axis("off")
plt.show()

霍夫变换_第4张图片

你可能感兴趣的:(opencv)