OpenCV(19):霍夫线变换

霍夫线变换是一种用来寻找直线的方法.

是用霍夫线变换之前, 首先要对图像进行边缘检测的处理,也即霍夫线变换的直接输入只能是边缘二值图像.

19.1 原理

众所周知, 一条直线在图像二维空间可由两个变量表示. 例如:

  1. 笛卡尔坐标系: 可由参数: (m,b) 斜率和截距表示.
  2. 极坐标系: 可由参数: (r,θ) 极径和极角表示

对于霍夫变换, 我们将用 极坐标系 来表示直线. 因此, 直线的表达式可为:


化简后得:


一般来说对于点 , 我们可以将通过这个点的一族直线统一定义为:


如果对于一个给定点   ,我们在极坐标对极径极角平面绘出所有通过它的直线, 将得到一条正弦曲线. 例如, 对于给定点 我们可以绘出下图 (在平面 ):

只绘出满足下列条件的点 

我们可以对图像中所有的点进行上述操作如果两个不同点进行上述操作后得到的曲线在平面 θ-r 相交, 这就意味着它们通过同一条直线

例如,接上面的例子我们继续对点 和点 绘图, 得到下图:

这三条曲线【坐标表示的是参数对 (θ,r )】在θ-r 平面相交于点 (0.925,9.6) ,则表明点 (x0,y0) 、点 (x1,y1) 和点 (x2,y2) 位于平面内的的同一条直线上。

那么以上的材料要说明什么呢? 这意味着一般来说, 一条直线能够通过在平面θ-r 寻找交于一点的曲线数量来 检测越多曲线交于一点也就意味着这个交点表示的直线由更多的点组成。一般来说我们可以通过设置直线上点的 阈值 来定义多少条曲线交于一点我们才认为 检测 到了一条直线

  1. 这就是霍夫线变换要做的。它追踪图像中每个点对应曲线间的交点,如果交于一点的曲线的数量超过了 阈值,那么可以认为这个交点所代表的参数对 ( )在原图像中为一条直线。

OpenCV实现了以下两种霍夫线变换:

  1. 标准霍夫线变换:原理在上面的部分已经说明了。它能给我们提供一组参数对(θ, )的集合来表示检测到的直线。在OpenCV 中通过函数 HoughLines 来实现。
  2. 统计概率霍夫线变换:这是执行起来效率更高的霍夫线变换. 它输出检测到的直线的端点  。在OpenCV 中它通过函数 HoughLinesP 来实现

19.2 cv2.HoughLines() 标准霍夫线变换

作用查找直线

原型:cv2.HoughLinesP(image, rho, theta, threshold)

参数

  1. image: 必须是二值图像,在使用hough变换之前,应用阈值或使用canny边缘检测,推荐使用canny边缘检测的结果图像; 
  2. rho: 为距离分辨率,double类型的,推荐用1.0 
  3. theta: 角度范围。以弧度为单位的角度精度,推荐用numpy.pi/180 
  4. threshod: 累加器阈值,累加平面的阈值参数,int类型,指可以被认为是一个线条的最小计数值。由于计数值的多少取决于线上的点数,所以这代表了可以被识别为线的最小长度。 超过设定阈值才被检测出线段,值越大,基本上意味着检出的线段越长,检出的线段个数越少。根据情况推荐先用100试试。

返回值

说明:

假设有一个100×100 的图片,有一条水平线在中间,获取这条线的第一个点,已知它的(x, y) 值,然后将θ = 0,1,2,……,180 放入线条方程中,获取r 值。对于每个(θ, )单元格,累加器中与之相关的(θ, )单元格每次增加的值为1,所以在累加器中,(90, 50) = 1 和一些其他单项相关联。

然后取线条上的第二个点,进行以上相同的动作,增加与之相关联的( )单元格,此时(90, 50) = 2 ,现在的操作都会增加( )的值。

继续为线条上的每个点进行相同的操作,在每个点,(90, 50) 单元格可以增值或者计数,其他单元格可能不会被计数。通过这种方式,最后(90, 50) 单元格会得到最大的计数。如果在计数器中搜索最大计数,就可以得到(90, 50) 的值,表示在距离原点50,90° 角的地方有一条线,如下图:

示例

import  cv2
import  numpy  as  np

img  =  cv2.imread('C:\\Users\\xxx\\Downloads\\contourImg.png')
gray  =  cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
edges  =  cv2.Canny(gray,50,150,apertureSize  =  3)

lines  =  cv2.HoughLines(edges,1,np.pi/180,78)
for i in range(0,len(lines)):
    rho,theta = lines[i][0][0],lines[i][0][1]
    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(img,(x1,y1),(x2,y2),(0,0,255),2)

cv.imshow('HoughLine',img)
cv.waitKey(0)
cv.destroyAllWindows()

运行结果如下:

19.3 cv2.HoughLinesP() 统计概率霍夫线变换

在霍夫变换中,可以通过2个变量来检测一条线上的点,但花费大量计算。概率霍夫变换是一个优化的霍夫变换,它不会计算所有的点,而是随机的选取一组足以识别直线的点,所以我们需要减少阈值。看下图中关于霍夫变换和概率霍夫变换在霍夫空间的比较:

OpenCV 技术是基于Matas, J. and Galambos, C. and Kittler, J.V.使用概率哈夫变换进行的线条鲁棒检测。它通过cv2.HoughLinesP()来实现,函数有2个新的参数。

  1. minLineLength - 线段的最小长度. Line segments shorter than this are rejected.
  2. maxLineGap - 使程序识别线段为一条线的线段之间最大的空隙

最好是这样,函数直接返回了线条的两个终点,在前面的实例中,必须找到所有的点,而只获取了线的参数。在这个实例中,所有的事都变得简单直接。

作用查找直线段

原型:

cv2.HoughLinesP(image, rho, theta, threshold, lines=None, minLineLength=None, maxLineGap=None)

参数

  1. image: 必须是二值图像,推荐使用canny边缘检测的结果图像; 
  2. rho: 线段以像素为单位的距离精度,double类型的,推荐用1.0 
  3. theta: 线段以弧度为单位的角度精度,推荐用numpy.pi/180 
  4. threshod: 累加平面的阈值参数,int类型,超过设定阈值才被检测出线段,值越大,基本上意味着检出的线段越长,检出的线段个数越少。根据情况推荐先用100试试
  5. lines:这个参数的意义未知,发现不同的lines对结果没影响,但是不要忽略了它的存在 
  6. minLineLength:线段以像素为单位的最小长度,根据应用场景设置 
  7. maxLineGap:同一方向上两条线段判定为一条线段的最大允许间隔(断裂),超过了设定值,则把两条线段当成一条线段,值越大,允许线段上的断裂越大,越有可能检出潜在的直线段

示例

import  cv2
import  numpy  as  np

img  =  cv2.imread('C:\\Users\\xxx\\Downloads\\contourImg.png')
gray  =  cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
edges  =  cv2.Canny(gray,50,150,apertureSize  =  3)
minLineLength  =  200
maxLineGap  =  10
lines  =  cv2.HoughLinesP(edges,1,np.pi/180,100,minLineLength,maxLineGap)
#for  x1,y1,x2,y2  in  lines[0]:
for i in range(0,len(lines)):
    for x1,y1,x2,y2  in  lines[i]:
        cv2.line(img,(x1,y1),(x2,y2),(0,255,255),5)

cv.imshow('HoughLineP',img)
cv.waitKey(0)
cv.destroyAllWindows()

 运行结果如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值