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