我正在使用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
答案 0 :(得分:11)
这里有点不对,所以我只是从头开始。
好的,打开图像后首先要做的是阈值处理。我强烈建议您再次查看tresholding上的OpenCV手册以及treshold methods的确切含义。
手册提到
cv2.threshold(src,thresh,maxval,type [,dst])→retval,dst
特殊值THRESH_OTSU可以与上述之一组合 值。在这种情况下,该函数确定最佳阈值 使用Otsu算法的值并使用它而不是指定的 打谷。
我知道它有点令人困惑,因为你不会将
想象一下,好像你在中午拍摄了一座大教堂或一座高楼的照片。在阳光明媚的日子,天空将非常明亮和蓝色,大教堂/建筑将会更加暗。这意味着属于天空的像素组将具有高亮度值,即将位于直方图的右侧,并且属于教堂的像素将更暗,即位于中间和左侧的像素。直方图。
Otsu使用它来尝试猜测正确的&#34;截止&#34;点,称为打谷。为了您的形象大津的阿尔格。假设地图一侧的所有白色都是背景,而地图本身就是前景。因此,阈值处理后的图像如下所示:
在此之后,不难猜出出了什么问题。但是,让我们继续吧,我相信,你想要实现的是这样的事情:
flag,b = cv2.threshold(gray,160,255,cv2.THRESH_BINARY)
然后你继续,并试图侵蚀图像。我不确定你为什么这样做,你的意图是&#34;大胆&#34;这些线条,或者是你打算消除噪音。在任何情况下,你从未将腐蚀的结果分配给某些东西。 Numpy数组,这是图像的表示方式,是可变的,但它不是语法的工作方式:
cv2.erode(src, kernel, [optionalOptions] ) → dst
所以你必须写:
b = cv2.erode(b,element)
好的,现在对于元素以及侵蚀是如何起作用的。侵蚀在图像上拖动内核。内核是一个简单的矩阵,其中有1&0; s和0&#39; s。该矩阵的一个元素,通常是中心元素,称为锚。锚是在操作结束时将被替换的元素。当你创建
cv2.getStructuringElement(cv2.MORPH_CROSS, (1, 1))
您创建的实际上是1x1矩阵(1列,1行)。这使侵蚀完全无用。
侵蚀是什么,首先从原始图像中检索像素亮度的所有值,其中与图像片段重叠的核心元素具有&#34; 1&#34;。然后它找到检索到的像素的最小值,并用该值替换锚点。
在您的情况下,这意味着您将[1]
矩阵拖到图像上,比较源图像像素亮度是否大于,等于或小于自身,然后将其替换为自身。
如果您打算删除&#34; noise&#34;,那么在图像上使用矩形内核可能会更好。可以这样想,&#34;噪音&#34;那是&#34;不适合&#34;与周围的环境。因此,如果您将中心像素与其周围环境进行比较,并且发现它不适合,那么它很可能是噪音。
此外,我已经说它用内核检索到的最小值替换了锚点。在数值上,最小值为0,这恰好是图像中黑色的表示方式。这意味着,在您的白色图像占主导地位的情况下,侵蚀会“膨胀”#34;黑色像素。如果它们在内核的范围内,则侵蚀将用具有0值黑色像素的255值白色像素替换。在任何情况下,它都不应该是形状(1,1)。
>>> cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
array([[0, 1, 0],
[1, 1, 1],
[0, 1, 0]], dtype=uint8)
如果我们用3x3矩形内核侵蚀第二个图像,我们会得到下面的图像。
好的,现在我们已经解决了这个问题,接下来你要做的就是使用Canny边缘检测找到边缘。你从中获得的图像是:
好的,现在我们寻找完全垂直和完全水平线仅。当然,除了图像左侧的子午线之外没有这样的线条(这就是所谓的吗?)和你做完右后的最终图像是这样的:
既然你从来没有描述过你的确切想法,我最好的猜测是你需要平行线和经线,你会在规模较小的地图上获得更多的运气,因为那些线条不是开头的,他们是曲线。另外,有没有特定的理由去做概率霍夫? &#34;常规&#34;霍夫不够吗?
很抱歉这个帖子太长了,希望有点帮助。
此处的文字被添加为11月24日OP的澄清请求。因为没有办法让答案符合char限制评论。
我建议OP提出一个更具体的问题来检测曲线因为你正在处理曲线op,而不是水平和垂直线。< / p>
有几种方法可以检测曲线,但没有一种方法很容易。按照从最简单到最难实施的顺序:
可能有更简单的方法,我以前从未真正处理过曲线检测。也许有一些技巧可以让你更轻松,我不知道。如果你问一个新的问题,那个尚未被关闭的问题你可能会有更多人注意到它。请确保就您感兴趣的确切主题提出完整而完整的问题。人们通常花费大量时间撰写如此广泛的主题。
为了向您展示如何使用Hough变换,请查看下面的内容:
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
条件绘制。将原始图像与绘制在其上的线条的图像进行比较时要特别注意。相似之处是不可思议的(嘿,得到它?)但是因为它们并不是很多,所以它看起来像垃圾。 (特别是检测到的最高纬度线看起来像它也是#34;角度&#34;但实际上这些线在其最厚点上与纬度线形成完美切线,就像霍夫算法所要求的那样)。承认使用线检测算法检测曲线存在限制