我正在使用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,而不是水平和垂直 线。
有几种检测曲线的方法,但都不是一件容易的事。从最容易实现到最困难的顺序:
可能有更简单的方法,我以前从未真正进行过曲线检测。我不知道,也许有一些技巧可以使它变得更容易。如果您提出一个新问题,但尚未结束作为一个答案,您可能会有更多的人注意到它。一定要问一个关于您感兴趣的确切主题的完整问题。人们通常不会花太多时间在如此广泛的主题上写作。
为了向您展示仅用霍夫变换就可以做什么,请查看下面的内容:
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条件绘制。比较原始图像和带有线条的图像时,请格外注意。相似之处是不可思议的(嘿,明白吗?),但是由于它们之间没有线条,所以很多相似之处只是看起来像垃圾。 (尤其是检测到的最高纬度线似乎过于“倾斜”,但实际上,正如霍夫算法所要求的那样,这些线在最粗点与纬线完美切线)。认识到使用线检测算法检测曲线存在局限性
