Pat*_*ins 22 opencv image-processing hough-transform straight-line-detection
我试图找到来自"文档"的图像的水平和垂直线.文档是从合同中扫描的页面,因此这些行看起来就像您在表格或合同块中看到的那样.
我一直在尝试OpenCV来完成这项工作.OpenCV中的Hough变换实现似乎对这项工作很有用,但是我找不到任何能够干净地找到垂直和水平线的参数组合.我尝试了边缘检测和不边缘检测.没运气.如果有人做过类似事情,我有兴趣知道如何做.
在这里看到我在OpenCV中使用HoughP进行实验之前和之后的图像.这是我能做的最好的,http://dl.dropbox.com/u/3787481/Untitled%201.png
所以现在我想知道是否有另一种我可以使用的变换,这将允许我可靠地找到水平和垂直线(并且最好也是虚线).
我知道这个问题是可以解决的,因为我有Nuance和ABBYY OCR工具,它们可以可靠地提取水平和垂直线并返回线条的边界框.
谢谢!帕特里克.
And*_*aev 30
您是否看过HoughLinesP函数文档中的代码示例?
我认为您可以将它作为算法的起点.要选择水平垂直线,您只需要按线角度过滤掉其他线条.
更新:
我认为你不需要在页面上找到线条而是水平的垂直边缘.对于此任务,您需要组合多个处理步骤以获得良好的结果.
对于您的图像,我可以通过将Canny边缘检测与HoughLinesP相结合来获得良好的结果.这是我的代码(我使用过python,但我认为你看到了这个想法):
img = cv2.imread("C:/temp/1.png")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 80, 120)
lines = cv2.HoughLinesP(edges, 1, math.pi/2, 2, None, 30, 1);
for line in lines[0]:
pt1 = (line[0],line[1])
pt2 = (line[2],line[3])
cv2.line(img, pt1, pt2, (0,0,255), 3)
cv2.imwrite("C:/temp/2.png", img)
Run Code Online (Sandbox Code Playgroud)
结果如下:

nat*_*ncy 12

这是使用形态学操作的完整 OpenCV 解决方案。
这是该过程的可视化。使用此输入图像:

二进制图像

import cv2
# Load image, convert to grayscale, Otsu's threshold
image = cv2.imread('1.png')
result = image.copy()
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
Run Code Online (Sandbox Code Playgroud)
检测到的水平线以绿色突出显示

# Detect horizontal lines
horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (40,1))
detect_horizontal = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, horizontal_kernel, iterations=2)
cnts = cv2.findContours(detect_horizontal, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
cv2.drawContours(result, [c], -1, (36,255,12), 2)
Run Code Online (Sandbox Code Playgroud)
检测到的垂直线以绿色突出显示

# Detect vertical lines
vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,10))
detect_vertical = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, vertical_kernel, iterations=2)
cnts = cv2.findContours(detect_vertical, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
cv2.drawContours(result, [c], -1, (36,255,12), 2)
Run Code Online (Sandbox Code Playgroud)
结果

这是使用另一个输入图像的输出
输入->二进制->检测水平->检测垂直->结果

注意:根据图像,您可能需要修改内核大小。例如,要捕获更长的水平线,可能需要将水平内核从(40, 1)增加到 say (80, 1)。如果你想检测更粗的水平线,那么你可以增加内核的宽度来说(80, 2). 此外,您可以在执行cv2.morphologyEx(). 同样,您可以修改垂直内核以检测更多或更少的垂直线。增加或减少内核大小时需要权衡,因为您可能会捕获更多或更少的行。同样,这一切都取决于输入图像
完整代码
import cv2
# Load image, convert to grayscale, Otsu's threshold
image = cv2.imread('1.png')
result = image.copy()
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
# Detect horizontal lines
horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (40,1))
detect_horizontal = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, horizontal_kernel, iterations=2)
cnts = cv2.findContours(detect_horizontal, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
cv2.drawContours(result, [c], -1, (36,255,12), 2)
# Detect vertical lines
vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,10))
detect_vertical = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, vertical_kernel, iterations=2)
cnts = cv2.findContours(detect_vertical, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
cv2.drawContours(result, [c], -1, (36,255,12), 2)
cv2.imshow('result', result)
cv2.waitKey()
Run Code Online (Sandbox Code Playgroud)
如果您只想要"线"而不是"线段",我会避免使用Canny,Hough,FindContours或任何其他此类函数,以防您希望代码更快.如果您的图像没有旋转,而您想要找到的图像总是垂直的或水平的,我只会使用cv :: Sobel(一个用于垂直,另一个用于水平)并为列和行创建累积数组.然后,您可以在此类累积或配置文件中搜索最大值,例如通过设置阈值,您将知道其中存在垂直或水平边线的行或列.
您可以考虑离开Hough线检测,因为此方法会查找"全局"线,而不一定是线段.我最近实施了一个识别"平行四边形"的应用程序 - 基本上可以旋转的正方形和由于视角而缩短的透视图.你可能会考虑类似的东西.我的管道是:
在您的应用程序中,生成的轮廓列表可能很大(取决于平滑的"侵略性"和Canny边缘检测器的特征增强.您可以通过各种参数修剪此列表:从轮廓查找器返回的点数轮廓区域(cvContourArea)等.根据我的经验,我希望应用程序中的"有效"线条具有明确定义的区域和顶点计数属性.此外,您可以根据末端之间的距离过滤出轮廓.点,由连接端点的线定义的角度等.
根据您拥有的CPU"时间",您可以始终将Hough算法与上述算法配对,以稳健地识别水平和垂直线.