Python OpenCV -- 霍夫线变换(十二)

本文详细介绍了霍夫线变换的基本原理及其在图像处理中的应用,包括标准霍夫线变换和概率霍夫变换两种方法,展示了如何使用OpenCV库在Python中实现这两种变换。

霍夫线变换

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

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


实现:

  1.  一条直线在图像二维空间可由两个变量表示. 例如:
       a.  在 笛卡尔坐标系: 可由参数: (m,b) 斜率和截距表示.
       b.  在 极坐标系: 可由参数: (r,\theta) 极径和极角表示

                                                                       

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

                                                                       

             化简得: r = x \cos \theta + y \sin \theta

 2.  一般来说对于点 (x_{0}, y_{0}), 我们可以将通过这个点的一族直线统一定义为:

                                          r_{\theta} = x_{0} \cdot \cos \theta  + y_{0} \cdot \sin \theta

    这就意味着每一对 (r_{\theta},\theta) 代表一条通过点 (x_{0}, y_{0}) 的直线.

3.    如果对于一个给定点 (x_{0}, y_{0}) 我们在极坐标对极径极角平面绘出所有通过它的直线, 将得到一条正弦曲线. 例如, 对于给定点 x_{0} = 8 and y_{0} = 6 我们可以绘出下图 (在平面 \theta - r):

                                                        

       只绘出满足下列条件的点 r > 0 and 0< \theta < 2 \pi.

  4. 我们可以对图像中所有的点进行上述操作. 如果两个不同点进行上述操作后得到的曲线在平面 \theta - r 相交, 这就意味着它们通过同一条直线. 例如, 接上面的例子我们继续对点: x_{1} = 9, y_{1} = 4 和点 x_{2} = 12, y_{2} = 3 绘图, 得到下图:

                                                          

     这三条曲线在 \theta - r 平面相交于点 (0.925, 9.6), 坐标表示的是参数对 (\theta, r) 或者是说点 (x_{0}, y_{0}), 点 (x_{1}, y_{1}) 和点 (x_{2}, y_{2}) 组成的平面内的的直线.

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


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


标准霍夫线变换和统计概率霍夫线变换

  a. 标准霍夫线变换

        原理在上面的部分已经说明了. 它能给我们提供一组参数对(\theta, r_{\theta})  的集合来表示检测到的直线

       在OpenCV 中通过函数 HoughLines 来实现


 b . 统计概率霍夫线变换

       这是执行起来效率更高的霍夫线变换. 它输出检测到的直线的端点 (x_{0}, y_{0}, x_{1}, y_{1})

      在OpenCV 中它通过函数 HoughLinesP 来实现


1. 标准霍夫线变换

    在Python 的 OpenCV版本中 标准霍夫线变换 函数为 cv2.HoughLines。它输入一幅含有点集的二值图(由非0像素表示),其中一些点互相联系组成直线。

通常这通过如 Canny 算子获得的一幅边缘图像。

   cv2.HoughLines 函数输出的是 [ float,float ] 形式的ndarray,其中每个值表示检测到的线(ρ,θ)中浮点值的参数。

示例:

#!/usr/bin/env python  
# encoding: utf-8  
import cv2  
import numpy as np 

img = cv2.imread("6.jpg", 0)  
  
img = cv2.GaussianBlur(img,(3,3),0)  
edges = cv2.Canny(img, 50, 150, apertureSize = 3)  

#(函数参数3和参数4) 通过步长为1的半径和步长为π/180的角来搜索所有可能的直线
#118 --是经过某一点曲线的数量的阈值
lines = cv2.HoughLines(edges,1,np.pi/180,118)  #这里对最后一个参数使用了经验型的值 
result = img.copy()  
for line in lines[0]: 
    rho = line[0] #第一个元素是距离rho  
    theta= line[1] #第二个元素是角度theta  
    print rho  
    print theta  
    if  (theta < (np.pi/4. )) or (theta > (3.*np.pi/4.0)): #垂直直线  
                #该直线与第一行的交点  
        pt1 = (int(rho/np.cos(theta)),0)  
        #该直线与最后一行的焦点  
        pt2 = (int((rho-result.shape[0]*np.sin(theta))/np.cos(theta)),result.shape[0])  
        #绘制一条白线  
        cv2.line( result, pt1, pt2, (255))  
    else: #水平直线  
        # 该直线与第一列的交点  
        pt1 = (0,int(rho/np.sin(theta)))  
        #该直线与最后一列的交点  
        pt2 = (result.shape[1], int((rho-result.shape[1]*np.cos(theta))/np.sin(theta)))  
        #绘制一条直线  
        cv2.line(result, pt1, pt2, (255), 1)  
  
cv2.imshow('Canny', edges )  
cv2.imshow('Result', result)  
cv2.waitKey(0)  
cv2.destroyAllWindows()  


效果图:


注意:

  在Opencv C++ 版本中,HoughLines 函数得到的结果是一个向量lines, 其中的元素是由两个元素组成的向量(rho , theta),所以 lines 的访问方式类似二维数组

std::vector<cv::Vec2f>::const_iterator it= lines.begin();  
float rho= (*it)[0];  
float theta= (*it)[1];  

 OpenCV Python 版本中,返回的是一个三维的 np.ndarray 。可通过检验HoughLines 返回的 lines 的 ndim 属性得到。

lines = cv2.HoughLines(edges,1,np.pi/180,118)  

# 输出结果
#lines.ndim属性  
(1, 5, 2) #lines.shape属性  
  
#lines[0]  
[[  4.20000000e+01   2.14675498e+00]  
 [  4.50000000e+01   2.14675498e+00]  
 [  3.50000000e+01   2.16420817e+00]  
 [  1.49000000e+02   1.60570288e+00]  
 [  2.24000000e+02   1.74532920e-01]]  
===============  
#lines本身  
[[[  4.20000000e+01   2.14675498e+00]  
  [  4.50000000e+01   2.14675498e+00]  
  [  3.50000000e+01   2.16420817e+00]  
  [  1.49000000e+02   1.60570288e+00]  
  [  2.24000000e+02   1.74532920e-01]]]  


1.概率霍夫变换

   通过上面的例子可以看出,其中 Hough 变换看起来就像在图像中查找对齐的边界像素点集合。但这样会在一些情况下导致虚假检测,如像素偶然对齐或多条直线

穿过同样的对齐像素造成的多重检测。

  要避免这样的问题,并检测图像中分段的直线(而不是贯穿整个图像的直线),由此出现了 概率 Hough 变换(Probabilistic Hough)

Python 版本中 由 cv2.HoughLinesP 实现:

#!/usr/bin/env python  
# encoding: utf-8  
import cv2  
import numpy as np 

img = cv2.imread("6.jpg")  
  
img = cv2.GaussianBlur(img,(3,3),0)  
edges = cv2.Canny(img, 50, 150, apertureSize = 3)  
lines = cv2.HoughLines(edges,1,np.pi/180,118)  
result = img.copy()  
  
#经验参数  
minLineLength = 200  
maxLineGap = 15  
lines = cv2.HoughLinesP(edges,1,np.pi/180,80,minLineLength,maxLineGap)  
for x1,y1,x2,y2 in lines[0]:  
    cv2.line(img,(x1,y1),(x2,y2),(0,255,0),2)  
  
cv2.imshow('Result', img)  
cv2.waitKey(0)  
cv2.destroyAllWindows() 

效果图:




本文参考和转载:
代码程序使用 sunny2038 博客所提供
http://blog.youkuaiyun.com/sunny2038/article/details/9253823
http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/imgproc/imgtrans/hough_lines/hough_lines.html

<think>好的,用户想用OpenCV-Python实现霍夫变换来检测图像中的矩形。首先,我需要回忆一下霍夫变换的相关知识。霍夫变换通常用于检测直线和圆形,检测矩形可能需要结合直线检测和一些后处理步骤。 用户提供的参考内容里提到了轮廓检测和直线检测,比如使用cv2.findContours和cv2.HoughLines。这可能对解决问题有帮助。首先,应该考虑图像预处理,比如灰度化、边缘检测。Canny边缘检测是常用的方法,参考内容里也有提到。 接下来,使用霍夫直线检测来找到图像中的直线。OpenCV的HoughLines或HoughLinesP函数可以检测直线,其中HoughLinesP是概率霍夫变换,效率更高,适合实时应用。检测到直线后,需要将这些直线组合成矩形。这可能需要计算直线的交点,或者寻找四边形的轮廓。 不过,用户提到的是检测矩形,或许另一种方法是先检测所有轮廓,然后筛选出四边形的轮廓,并进一步验证其是否为矩形。参考内容中的cv2.findContours和轮廓近似方法可能适用。比如,使用cv2.approxPolyDP来近似轮廓,如果近似后的轮廓有四个顶点,且角度接近直角,则可以认为是矩形。 需要结合两种方法:霍夫变换检测直线,然后找出四条直线形成矩形;或者使用轮廓检测直接找四边形。用户明确提到霍夫变换,所以可能需要优先考虑直线检测的方法。但霍夫变换检测直线后如何组合成矩形,这可能需要计算直线的交点和角度,找出相互垂直且闭合的四边形。 同时,注意图像预处理的重要性,比如降噪、二值化等,参考内容里提到使用二值化来提取硬币轮廓,可能同样适用于矩形检测。此外,处理后的边缘图像质量直接影响霍夫变换的效果。 然后,编写代码步骤可能包括:读取图像,转为灰度,高斯模糊,Canny边缘检测,霍夫变换检测直线,处理直线数据,寻找四个边组成矩形,绘制结果。或者,检测所有直线后,通过筛选水平和垂直的直线,再组合成矩形。 需要注意的是,霍夫变换可能会检测到很多直线,如何筛选出构成矩形的四条是一个挑战。可能需要计算直线之间的交点和角度关系,或者使用其他几何条件来过滤。 另外,用户提供的引用中提到cv.RETR_EXTERNAL和轮廓填充,这可能与轮廓检测方法相关。如果使用轮廓检测,步骤可能更简单:找到轮廓,近似多边形,筛选四个点的轮廓,计算角度是否为直角,面积是否足够大等。 不过用户明确要求使用霍夫变换,所以可能需要将两种方法结合,比如用霍夫检测直线,然后找到四个直线形成矩形,或者用霍夫检测矩形的方法。不过OpenCV中是否有直接的霍夫矩形检测函数?我记得HoughLines和HoughLinesP主要用于直线,而矩形检测可能需要其他处理。 综合以上思考,解决方案可能是:预处理图像,检测边缘,使用霍夫变换检测直线,然后通过直线之间的几何关系筛选出可能的矩形边,最后验证并绘制矩形。或者,检测直线后,寻找闭合的四边形。 现在需要将这些步骤转化为具体的代码示例,并确保正确引用用户提供的参考资料中的方法,比如使用cv2.findContours中的参数,或者边缘检测的处理步骤。同时,注意回答的结构,按照用户的要求,分步骤说明,并生成相关问题。</think>以下是用OpenCV-Python实现霍夫变换检测矩形的分步说明: ### 霍夫变换检测矩形步骤 1. **图像预处理** ```python import cv2 import numpy as np # 读取图像并转为灰度 img = cv2.imread('rect.jpg') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 高斯模糊降噪 blur = cv2.GaussianBlur(gray, (5,5), 0) # Canny边缘检测(参数根据实际情况调整) edges = cv2.Canny(blur, 50, 150) ``` 2. **霍夫直线检测** ```python # 概率霍夫变换检测直线 lines = cv2.HoughLinesP(edges, rho=1, theta=np.pi/180, threshold=50, minLineLength=50, maxLineGap=10) # 绘制所有检测到的直线 if lines is not None: for line in lines: x1,y1,x2,y2 = line[0] cv2.line(img, (x1,y1), (x2,y2), (0,255,0), 2) ``` 3. **直线后处理(关键步骤)** - **筛选水平和垂直线**:计算直线角度,保留0°、90°、45°等特定角度的直线 - **寻找交点**:通过直线方程计算交点,组合成四边形 - **几何验证**:验证四边形内角是否接近90°,边长比例是否符合矩形特征 4. **替代方案:轮廓检测法** ```python # 查找轮廓并筛选矩形 contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) for cnt in contours: # 轮廓近似 epsilon = 0.02*cv2.arcLength(cnt,True) approx = cv2.approxPolyDP(cnt,epsilon,True) # 筛选四边形 if len(approx) == 4: # 计算角度验证直角 cv2.drawContours(img, [approx], 0, (0,0,255), 3) ``` 5. **结果显示** ```python cv2.imshow('Result', img) cv2.waitKey(0) cv2.destroyAllWindows() ``` > 注意:实际应用中需要根据具体图像调整参数,建议结合两种方法: > 1. 先用霍夫变换检测直线 > 2. 再用轮廓分析验证几何特征[^2]
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值