OpenCV—直线检测

  • Post author:
  • Post category:其他



OpenCV—直线检测

原文链接:

opencv直线检测

直线检测相关


Opencv学习笔记—–霍夫变换直线检测及原理理解


OpenCV-Python教程(9、使用霍夫变换检测直线)

Hough变换是经典的检测直线的算法。其最初用来检测图像中的直线,同时也可以将其扩展,以用来检测图像中简单的结构。



变换图示

霍夫直线检测的两种方法

1.获取灰度图像
2.canny边缘检测
3.获取霍夫直线信息
4.算出直线位置,画出每条直线

一:HoughLines霍夫变换

def line_detection(image):
    gray </span>=<span style="color: rgb(0, 0, 0); --darkreader-inline-color:#ffffff;" data-darkreader-inline-color=""> cv.cvtColor(image,cv.COLOR_BGR2GRAY)
    edges </span>= cv.Canny(gray,<span style="color: rgb(128, 0, 128); --darkreader-inline-color:#ffabff;" data-darkreader-inline-color="">50</span>,<span style="color: rgb(128, 0, 128); --darkreader-inline-color:#ffabff;" data-darkreader-inline-color="">150</span>,apertureSize=<span style="color: rgb(128, 0, 128); --darkreader-inline-color:#ffabff;" data-darkreader-inline-color="">3</span>)    #apertureSize是sobel算子大小,只能为1,<span style="color: rgb(128, 0, 128); --darkreader-inline-color:#ffabff;" data-darkreader-inline-color="">3</span>,<span style="color: rgb(128, 0, 128); --darkreader-inline-color:#ffabff;" data-darkreader-inline-color="">5</span><span style="color: rgb(128, 0, 128); --darkreader-inline-color:#ffabff;" data-darkreader-inline-color="">7</span><span style="color: rgb(0, 0, 0); --darkreader-inline-color:#ffffff;" data-darkreader-inline-color="">
    lines </span>= cv.HoughLines(edges,<span style="color: rgb(128, 0, 128); --darkreader-inline-color:#ffabff;" data-darkreader-inline-color="">1</span>,np.pi/<span style="color: rgb(128, 0, 128); --darkreader-inline-color:#ffabff;" data-darkreader-inline-color="">180</span>,<span style="color: rgb(128, 0, 128); --darkreader-inline-color:#ffabff;" data-darkreader-inline-color="">200</span><span style="color: rgb(0, 0, 0); --darkreader-inline-color:#ffffff;" data-darkreader-inline-color="">)  #函数将通过步长为1的半径和步长为π/180的角来搜索所有可能的直线
    </span><span style="color: rgb(0, 0, 255); --darkreader-inline-color:#4dbbff;" data-darkreader-inline-color="">for</span> line <span style="color: rgb(0, 0, 255); --darkreader-inline-color:#4dbbff;" data-darkreader-inline-color="">in</span><span style="color: rgb(0, 0, 0); --darkreader-inline-color:#ffffff;" data-darkreader-inline-color=""> lines:
        <span style="color: rgb(255, 0, 0); --darkreader-inline-color:#ff2727;" data-darkreader-inline-color="">rho,theta </span></span><span style="color: rgb(255, 0, 0); --darkreader-inline-color:#ff2727;" data-darkreader-inline-color="">= line[0]  #获取极值ρ长度和θ角度
        a = np.cos(theta)  #获取角度cos值
        b = np.sin(theta)  #获取角度sin值
        x0 = a * rho  #获取x轴值
        y0 = b * rho  #获取y轴值  x0和y0是直线的中点
        x1 = int(x0 + 1000*(-b))  #获取这条直线最大值点x1
        y1 = int(y0 + 1000*(a))   #获取这条直线最大值点y1
        x2 = int(x0 - 1000 * (-b))  #获取这条直线最小值点x2  
        y2 = int(y0 - 1000 *</span><span style="color: rgb(0, 0, 0); --darkreader-inline-color:#ffffff;" data-darkreader-inline-color=""><span style="color: rgb(255, 0, 0); --darkreader-inline-color:#ff2727;" data-darkreader-inline-color=""> (a))  #获取这条直线最小值点y2  其中*1000是内部规则</span>
        cv.line(image,(x1,y1),(x2,y2),(</span><span style="color: rgb(128, 0, 128); --darkreader-inline-color:#ffabff;" data-darkreader-inline-color="">0</span>,<span style="color: rgb(128, 0, 128); --darkreader-inline-color:#ffabff;" data-darkreader-inline-color="">0</span>,<span style="color: rgb(128, 0, 128); --darkreader-inline-color:#ffabff;" data-darkreader-inline-color="">255</span>),<span style="color: rgb(128, 0, 128); --darkreader-inline-color:#ffabff;" data-darkreader-inline-color="">2</span><span style="color: rgb(0, 0, 0); --darkreader-inline-color:#ffffff;" data-darkreader-inline-color="">)  <span style="color: rgb(255, 0, 0); --darkreader-inline-color:#ff2727;" data-darkreader-inline-color="">#开始划线</span>
    cv.imshow(</span><span style="color: rgb(128, 0, 0); --darkreader-inline-color:#ffabab;" data-darkreader-inline-color="">"</span><span style="color: rgb(128, 0, 0); --darkreader-inline-color:#ffabab;" data-darkreader-inline-color="">image line</span><span style="color: rgb(128, 0, 0); --darkreader-inline-color:#ffabab;" data-darkreader-inline-color="">"</span><span style="color: rgb(0, 0, 0); --darkreader-inline-color:#ffffff;" data-darkreader-inline-color="">,image)



src </span>= cv.imread(<span style="color: rgb(128, 0, 0); --darkreader-inline-color:#ffabab;" data-darkreader-inline-color="">"</span><span style="color: rgb(128, 0, 0); --darkreader-inline-color:#ffabab;" data-darkreader-inline-color="">./l.png</span><span style="color: rgb(128, 0, 0); --darkreader-inline-color:#ffabab;" data-darkreader-inline-color="">"</span><span style="color: rgb(0, 0, 0); --darkreader-inline-color:#ffffff;" data-darkreader-inline-color="">)  #读取图片
cv.namedWindow(</span><span style="color: rgb(128, 0, 0); --darkreader-inline-color:#ffabab;" data-darkreader-inline-color="">"</span><span style="color: rgb(128, 0, 0); --darkreader-inline-color:#ffabab;" data-darkreader-inline-color="">input image</span><span style="color: rgb(128, 0, 0); --darkreader-inline-color:#ffabab;" data-darkreader-inline-color="">"</span><span style="color: rgb(0, 0, 0); --darkreader-inline-color:#ffffff;" data-darkreader-inline-color="">,cv.WINDOW_AUTOSIZE)    #创建GUI窗口,形式为自适应
cv.imshow(</span><span style="color: rgb(128, 0, 0); --darkreader-inline-color:#ffabab;" data-darkreader-inline-color="">"</span><span style="color: rgb(128, 0, 0); --darkreader-inline-color:#ffabab;" data-darkreader-inline-color="">input image</span><span style="color: rgb(128, 0, 0); --darkreader-inline-color:#ffabab;" data-darkreader-inline-color="">"</span><span style="color: rgb(0, 0, 0); --darkreader-inline-color:#ffffff;" data-darkreader-inline-color="">,src)    #通过名字将图像和窗口联系

line_detect_possible_demo(src)

cv.waitKey(</span><span style="color: rgb(128, 0, 128); --darkreader-inline-color:#ffabff;" data-darkreader-inline-color="">0</span><span style="color: rgb(0, 0, 0); --darkreader-inline-color:#ffffff;" data-darkreader-inline-color="">)   #等待用户操作,里面等待参数是毫秒,我们填写0,代表是永远,等待用户操作
cv.destroyAllWindows()  #销毁所有窗口</span></pre><div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><a href="javascript:void(0);" onclick="copyCnblogsCode(this)" title="复制代码"><img src="//common.cnblogs.com/images/copycode.gif" alt="复制代码"></a></span></div></div>

相关知识补充

(一)HoughLines方法

def HoughLines(image, rho, theta, threshold, lines=None, srn=None, stn=None, min_theta=None, max_theta=None): # real signature unknown; restored from __doc__

cv.HoughLines(edges,1,np.pi/180,200)

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

第一个参数image:是canny边缘检测后的图像

第二个参数rho和第三个参数theta:对应直线搜索的步长。在本例中,函数将通过步长为1的半径和步长为π/180的角来搜索所有可能的直线。

最后一个参数threshold:是经过某一点曲线的数量的阈值,超过这个阈值,就表示这个交点所代表的参数对(rho, theta)在原图像中为一条直线

观察前面的例子得到的结果图片,其中Hough变换看起来就像在图像中查找对齐的边界像素点集合。
但这样会在一些情况下导致虚假检测,如像素偶然对齐或多条直线穿过同样的对齐像素造成的多重检测。

二:HoughLinesP概率霍夫变换(是加强版)使用简单,效果更好,检测图像中分段的直线(而不是贯穿整个图像的直线)

def line_detect_possible_demo(image):
    gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
    edges = cv.Canny(gray, 50, 150, apertureSize=3)  # apertureSize是sobel算子大小,只能为1,3,5,7
    lines = cv.HoughLinesP(edges, 1, np.pi / 180, 100, minLineLength=50,maxLineGap=10)  #函数将通过步长为1的半径和步长为π/180的角来搜索所有可能的直线
    for line in lines:
        print(type(line))   #多维数组
        x1,y1,x2,y2 = line[0]
        cv.line(image,(x1,y1),(x2,y2),(0,0,255),2)
    cv.imshow("line_detect_possible_demo",image)

相关知识补充:

(一)HoughLinesP方法

def HoughLinesP(image, rho, theta, threshold, lines=None, minLineLength=None, maxLineGap=None): # real signature unknown; restored from __doc__

cv.HoughLinesP(edges, 1, np.pi / 180, 100, minLineLength=50,maxLineGap=10)

第一个参数是需要处理的原图像,该图像必须为cannay边缘检测后的图像;

第二和第三参数:步长为1的半径和步长为π/180的角来搜索所有可能的直线

第四个参数是阈值,概念同霍夫变换

第五个参数:minLineLength-线的最短长度,比这个线短的都会被忽略。

第六个参数:maxLineGap-两条线之间的最大间隔,如果小于此值,这两条线就会被看成一条线。

这个函数的返回值就是直线的起点和终点。

作者:

山上有风景


欢迎任何形式的转载,但请务必注明出处。

限于本人水平,如果文章和代码有表述不当之处,还请不吝赐教。