Skip to main content
 首页 » 编程设计

python之Python OpenCV HoughLinesP无法检测线

2025年05月04日9xing901022

我正在使用OpenCV HoughlinesP查找水平和垂直线。大多数时间都找不到任何行。即使找到一条线,它甚至也不接近实际图像。

import cv2 
import numpy as np 
 
img = cv2.imread('image_with_edges.jpg') 
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) 
 
 
flag,b = cv2.threshold(gray,0,255,cv2.THRESH_OTSU) 
 
element = cv2.getStructuringElement(cv2.MORPH_CROSS,(1,1)) 
cv2.erode(b,element) 
 
edges = cv2.Canny(b,10,100,apertureSize = 3) 
 
lines = cv2.HoughLinesP(edges,1,np.pi/2,275, minLineLength = 100, maxLineGap = 200)[0].tolist() 
 
for x1,y1,x2,y2 in lines: 
   for index, (x3,y3,x4,y4) in enumerate(lines): 
 
    if y1==y2 and y3==y4: # Horizontal Lines 
        diff = abs(y1-y3) 
    elif x1==x2 and x3==x4: # Vertical Lines 
        diff = abs(x1-x3) 
    else: 
        diff = 0 
 
    if diff < 10 and diff is not 0: 
        del lines[index] 
 
    gridsize = (len(lines) - 2) / 2 
 
   cv2.line(img,(x1,y1),(x2,y2),(0,0,255),2) 
   cv2.imwrite('houghlines3.jpg',img) 

输入图片:


输出图像:(请参见红线):


@ljetibo尝试使用:
c_6.jpg

请您参考如下方法:

这里有很多错误,所以我将从头开始。

好的,打开图像后要做的第一件事就是打招呼。我强烈建议您再看看tresholding上的OpenCV手册以及treshold methods的确切含义。

手册中提到

cv2.threshold(src, thresh, maxval, type[, dst]) → retval, dst

the special value THRESH_OTSU may be combined with one of the above values. In this case, the function determines the optimal threshold value using the Otsu’s algorithm and uses it instead of the specified thresh .



我知道这有点令人困惑,因为您没有将THRESH_OTSU与其他任何方法(THRESH_BINARY等)有效地组合在一起,不幸的是,手册可能是这样。此方法实际执行的操作是假设存在一个“前景”和一个“背景”,它们遵循双峰直方图,然后应用我认为的THRESH_BINARY。

想象一下,就好像您正在拍摄大教堂或高层建筑物的图像。在阳光明媚的日子里,天空将非常明亮和蔚蓝,而大教堂/建筑将变得更暗。这意味着属于天空的像素组都将具有较高的亮度值,即在直方图的右侧,而属于教堂的像素将较暗,即位于像素组的中间和左侧。直方图。

Otsu使用此方法尝试猜测正确的“临界”点(称为脱粒)。对于您的图像,大津的业务。假设 map 侧面的所有白色都是背景,而 map 本身就是前景。因此,阈值化后的图像如下所示:



在此之后,不难猜测出了什么问题。但是,让我们继续,我相信您想要实现的目标是这样的:
flag,b = cv2.threshold(gray,160,255,cv2.THRESH_BINARY) 



然后继续,尝试侵 eclipse 图像。我不确定为什么要这样做,是要“加粗”线条还是要消除噪音。无论如何,您从未将腐 eclipse 的结果分配给某些东西。 numpy数组是表示图像的方式,是可变的,但语法不是这样的:
cv2.erode(src, kernel, [optionalOptions] ) → dst 

所以你必须写:
b = cv2.erode(b,element) 

好了,现在介绍元素以及侵 eclipse 如何发生。侵 eclipse 将内核拖到图像上。内核是一个简单的矩阵,其中包含1和0。该矩阵的元素之一(通常为中心)称为 anchor 。 anchor 是在操作结束时将被替换的元素。创建时
cv2.getStructuringElement(cv2.MORPH_CROSS, (1, 1)) 

您创建的实际上是一个1x1矩阵(1列1行)。这使得腐 eclipse 完全无用。

腐 eclipse 的作用是,首先从原始图像中检索所有像素亮度值,其中与图像段重叠的内核元素的值为“1”。然后,它找到检索到的像素的最小值,并用该值替换 anchor 。

在您的情况下,这意味着您将 [1]矩阵拖到图像上,比较源图像像素的亮度是否大于,等于或小于其自身,然后将其替换为自身。

如果您打算去除“噪音”,那么最好在图像上使用矩形内核。这样想,“噪音”就是“不适合”周围环境的东西。因此,如果将中心像素与周围环境进行比较,发现它不合适,则很可能是噪声。

此外,我已经说过用内核获取的最小值替换 anchor 。在数值上,最小值是0,这恰好是图像中黑色的表示方式。这意味着在您的图像主要为白色的情况下,腐 eclipse 会“膨胀”黑色像素。如果在内核可及范围内,侵 eclipse 会将255个值的白色像素替换为0个值的黑色像素。无论如何,它永远都不应该是形状(1,1)。
>>> cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3)) 
array([[0, 1, 0], 
       [1, 1, 1], 
       [0, 1, 0]], dtype=uint8) 

如果我们用3x3矩形核腐 eclipse 第二张图像,则会得到下面的图像。



好的,现在我们解决了这个问题,接下来要做的就是使用Canny边缘检测找到边缘。从中获得的图像是:



好的,现在我们寻找 EXACTLY 垂直线和 EXACTLY 水平线 仅。当然,除了图像左侧的子午线以外没有其他线条(就是所谓的吗?),正确处理后得到的最终图像将是:



现在,由于您从未描述过确切的想法,而我最好的猜测是您想要平行线和子午线,因此在比例较小的 map 上会获得更多的运气,因为这些不是以直线开头的,而是曲线。此外,是否有特定原因可以完成概率霍夫测验? “常规”霍夫还不够吗?

对太长的帖子表示抱歉,希望对您有所帮助。

从11月24日起,在此处添加文字作为澄清请求。因为没有办法将答案放入字符有限的评论中。

我建议OP提出一个更特定于 曲线的检测的新问题,因为您要处理的是曲线op,而不是水平和垂直 线。

有几种检测曲线的方法,但都不是一件容易的事。从最容易实现到最困难的顺序:
  • 使用RANSAC算法。制定一个描述多头性质的公式。和拉特。线取决于所讨论的 map 。即当您靠近赤道时,纬度曲线几乎是 map 上的一条完美的直线,赤道是一条完美的直线,但是当您处于高纬度时(极点附近),它将非常弯曲,类似于圆弧段)。 SciPy已经将RANSAC实现为一个类,您所要做的就是查找并以编程方式定义要尝试拟合曲线的模型。当然,还有经常使用的4dummies文本here。这是最简单的,因为您要做的就是数学。
  • 很难做的是创建一个矩形网格,然后尝试使用cv findHomography将网格扭曲到图像上的适当位置。对于各种几何变换,您可以对网格进行处理,可以 check out OpenCv manual。这是一种“骇人”的方法,可能比1更糟糕。因为它取决于您可以重新创建一个网格的事实,该网格上有足够的细节和对象,cv可以识别您尝试的图像上的结构扭曲它。这需要您执行与1.类似的数学运算,并且只需执行少量编码即可从几种不同的函数中构成最终解决方案。
  • 实际上要这样做。在数学上有很整洁的方式将曲线描述为曲线上的切线列表。您可以尝试将一堆较短的HoughLines拟合到图像或图像段中,然后尝试对所有找到的线进行分组,并通过假定它们与曲线相切来确定它们是否确实遵循所需形状的曲线或他们随机。有关此问题,请参见this paper。在所有方法中,这是最困难的,因为它需要大量的单独编码和一些数学方法。

  • 可能有更简单的方法,我以前从未真正进行过曲线检测。我不知道,也许有一些技巧可以使它变得更容易。如果您提出一个新问题,但尚未结束作为一个答案,您可能会有更多的人注意到它。一定要问一个关于您感兴趣的确切主题的完整问题。人们通常不会花太多时间在如此广泛的主题上写作。

    为了向您展示仅用霍夫变换就可以做什么,请查看下面的内容:
    import cv2 
    import numpy as np 
     
    def draw_lines(hough, image, nlines): 
       n_x, n_y=image.shape 
       #convert to color image so that you can see the lines 
       draw_im = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR) 
     
       for (rho, theta) in hough[0][:nlines]: 
          try: 
             x0 = np.cos(theta)*rho 
             y0 = np.sin(theta)*rho 
             pt1 = ( int(x0 + (n_x+n_y)*(-np.sin(theta))), 
                     int(y0 + (n_x+n_y)*np.cos(theta)) ) 
             pt2 = ( int(x0 - (n_x+n_y)*(-np.sin(theta))), 
                     int(y0 - (n_x+n_y)*np.cos(theta)) ) 
             alph = np.arctan( (pt2[1]-pt1[1])/( pt2[0]-pt1[0]) ) 
             alphdeg = alph*180/np.pi 
             #OpenCv uses weird angle system, see: http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_imgproc/py_houghlines/py_houghlines.html 
             if abs( np.cos( alph - 180 )) > 0.8: #0.995: 
                cv2.line(draw_im, pt1, pt2, (255,0,0), 2) 
             if rho>0 and abs( np.cos( alphdeg - 90)) > 0.7: 
                cv2.line(draw_im, pt1, pt2, (0,0,255), 2)     
          except: 
             pass 
       cv2.imwrite("/home/dino/Desktop/3HoughLines.png", draw_im, 
                 [cv2.IMWRITE_PNG_COMPRESSION, 12])    
     
    img = cv2.imread('a.jpg') 
    gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) 
     
    flag,b = cv2.threshold(gray,160,255,cv2.THRESH_BINARY) 
    cv2.imwrite("1tresh.jpg", b) 
     
    element = np.ones((3,3)) 
    b = cv2.erode(b,element) 
    cv2.imwrite("2erodedtresh.jpg", b) 
     
    edges = cv2.Canny(b,10,100,apertureSize = 3) 
    cv2.imwrite("3Canny.jpg", edges) 
     
    hough = cv2.HoughLines(edges, 1, np.pi/180, 200)    
    draw_lines(hough, b, 100) 
    

    从波纹管中可以看到,直线只是经度。纬度不是直线,因此对于每个纬度,您都有几条检测到的线表现得像直线上的切线。蓝色绘制的线由​​ if abs( np.cos( alph - 180 )) > 0.8:绘制,而红色绘制的线由​​ rho>0 and abs( np.cos( alphdeg - 90)) > 0.7条件绘制。比较原始图像和带有线条的图像时,请格外注意。相似之处是不可思议的(嘿,明白吗?),但是由于它们之间没有线条,所以很多相似之处只是看起来像垃圾。 (尤其是检测到的最高纬度线似乎过于“倾斜”,但实际上,正如霍夫算法所要求的那样,这些线在最粗点与纬线完美切线)。认识到使用线检测算法检测曲线存在局限性