Python OpenCV HoughLinesP 无法检测直线

2024-02-01

我正在使用 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)

Input Image: input image

Output Image: (see the Red Line): enter image description here

@ljetibo 试试这个:c_6.jpg http://www.lib.utexas.edu/maps/onc/txu-pclmaps-oclc-8322829_c_6.jpg


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

好的,打开图像后要做的第一件事就是阈值化。我强烈建议您再看一下 OpenCV 手册阈值化 http://docs.opencv.org/2.4/doc/tutorials/imgproc/threshold/threshold.html以及其确切含义阈值法 http://docs.opencv.org/2.4/modules/imgproc/doc/miscellaneous_transformations.html?highlight=threshold#threshold.

手册中提到

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

特殊值 THRESH_OTSU 可以与上述之一组合 价值观。在这种情况下,该函数确定最佳阈值 使用大津算法的值并使用它代替指定的 脱粒。

我知道这有点令人困惑,因为你实际上并没有combineTHRESH_OTSU 与任何其他方法(THRESH_BINARY 等...),不幸的是该手册可能是这样的。这个方法实际上所做的是假设有一个“前景”和一个“背景”遵循双峰直方图,然后应用我相信的 THRESH_BINARY。

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

大津用它来尝试猜测正确的“截止”点,称为脱粒点。对于你的形象大津的阿尔格。假设地图一侧的所有白色都是背景,地图本身是前景。因此,阈值处理后的图像如下所示:

过了这一点,就不难猜出出了什么问题。但让我们继续,我相信你想要实现的是这样的:

flag,b = cv2.threshold(gray,160,255,cv2.THRESH_BINARY)

然后你继续,并试图侵蚀这个形象。我不确定你为什么要这样做,是为了“加粗”线条,还是为了消除噪音。无论如何,你从未将侵蚀的结果分配给某物。 Numpy 数组(图像的表示方式)是可变的,但这不是语法的工作方式:

cv2.erode(src, kernel, [optionalOptions] ) → dst

所以你必须写:

b = cv2.erode(b,element)

好的,现在介绍元素以及侵蚀的工作原理。腐蚀将内核拖到图像上。内核是一个简单的矩阵,其中有 1 和 0。该矩阵的元素之一(通常是中心元素)称为锚点。锚点是在操作结束时将被替换的元素。当你创建时

cv2.getStructuringElement(cv2.MORPH_CROSS, (1, 1))

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

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

就您而言,这意味着您拖动[1]图像上的矩阵,比较源图像像素亮度是否大于、等于或小于自身,然后将其替换为自身。

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

此外,我说过它用内核检索到的最小值替换了锚点。从数值上看,最小值为 0,这恰好是图像中黑色的表示方式。这意味着,在您的图像以白色为主的情况下,侵蚀会使黑色像素“膨胀”。如果 255 值的白色像素位于内核的范围内,则侵蚀会将 0 值的黑色像素替换为 0 值的黑色像素。无论如何,它不应该是 (1,1) 形状。

>>> cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
array([[0, 1, 0],
       [1, 1, 1],
       [0, 1, 0]], dtype=uint8)

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

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

好的,现在我们寻找EXACTLY垂直和EXACTLY水平线ONLY。当然,除了图像左侧的经线(这就是它的名字?)之外,没有这样的线,正确操作后得到的最终图像将是这样的:

现在,由于您从未描述过您的确切想法,而我最好的猜测是您想要平行线和经线,因此在较小比例的地图上您会更幸运,因为这些不是直线,而是曲线。此外,是否有完成概率霍夫的具体原因? “常规”霍夫还不够吗?

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


此处的文本是作为 11 月 24 日 OP 的澄清请求而添加的。因为没有办法将答案放入有限的注释中。

我建议OP提出一个更具体的新问题来检测curves因为你处理的是曲线,而不是水平和垂直lines.

有多种方法可以检测曲线,但没有一种方法是简单的。按照从最简单到最难的顺序:

  1. 使用RANSAC算法。开发一个描述多头性质的公式。和纬度。线路取决于相关地图。 IE。当您靠近赤道时,纬度曲线在地图上几乎是一条完美的直线,赤道是完美的直线,但当您位于高纬度地区(靠近两极)时,纬度曲线将非常弯曲,类似于圆段)。 SciPy 已经有了RANSAC http://scipy-cookbook.readthedocs.org/items/RANSAC.html作为一个类实现,您所要做的就是找到并以编程方式定义您想要尝试拟合曲线的模型。当然还有永远有用的 4dummies 文本here http://old.vision.ece.ucsb.edu/~zuliani/Research/RANSAC/docs/RANSAC4Dummies.pdf。这是最简单的,因为您所要做的就是数学。
  2. 有点困难的是创建一个矩形网格,然后尝试使用 cv findHomography 将网格扭曲到图像上的适当位置。对于可以对网格进行的各种几何变换,您可以查看OpenCV 手册 http://docs.opencv.org/2.4/modules/imgproc/doc/geometric_transformations.html。这是一种黑客方法,可能比 1. 效果更差,因为它取决于这样一个事实:您可以重新创建一个包含足够细节和对象的网格,以便 cv 可以识别您正在尝试的图像上的结构将其扭曲到。这需要您执行与 1. 类似的数学运算,并且只需进行一些编码即可由几个不同的函数组成最终解决方案。
  3. 真正做到这一点。有一些数学上简洁的方法可以将曲线描述为曲线上的切线列表。您可以尝试将一堆较短的 HoughLines 拟合到图像或图像片段中,然后尝试对所有找到的线进行分组,并通过假设它们与曲线相切来确定它们是否确实遵循所需形状的曲线或者是他们随机的。看这张纸 http://arxiv.org/pdf/1501.03124.pdf在这个问题上。在所有方法中,这种方法是最难的,因为它需要大量的单独编码和一些关于该方法的数学运算。

可能有更简单的方法,我以前从未真正处理过曲线检测。也许有一些技巧可以让事情变得更容易,我不知道。如果你提出一个新问题,一个尚未作为答案结束的问题,你可能会有更多的人注意到它。请务必针对您感兴趣的确切主题提出完整且完整的问题。人们通常不会花那么多时间就如此广泛的主题进行写作。

为了向您展示仅使用霍夫变换可以做什么,请查看以下内容:

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健康)状况。将原始图像与画有线条的图像进行比较时要密切注意。这种相似度是不可思议的(嘿,明白了吗?),但因为它们不是台词,所以很多看起来只是垃圾。 (尤其是检测到的最高纬度线,看起来太“有角度”,但实际上这些线在其最粗点上与纬度线完美相切,正如霍夫算法所要求的那样)。承认使用直线检测算法检测曲线存在局限性

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python OpenCV HoughLinesP 无法检测直线 的相关文章

随机推荐