Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/opencv/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/image-processing/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
基于OpenCV的水平线检测_Opencv_Image Processing_Hough Transform_Straight Line Detection - Fatal编程技术网

基于OpenCV的水平线检测

基于OpenCV的水平线检测,opencv,image-processing,hough-transform,straight-line-detection,Opencv,Image Processing,Hough Transform,Straight Line Detection,我试图从一张来自“文档”的图像中找到水平线和垂直线。文档是从合同中扫描出来的页面,因此这些行看起来就像您在表或合同块中看到的一样 我一直在为这份工作尝试OpenCV。OpenCV中的Hough变换实现似乎对这项工作很有用,但我找不到任何参数组合,使它能够清晰地找到垂直线和水平线。我尝试了使用和不使用边缘检测。不走运。如果有人做过类似的事情,我很想知道怎么做 在这里可以看到我在OpenCV中使用HoughP进行实验前后的图像。这是我能做的最好的了 所以现在我想知道是否有另一种变换可以让我可靠地找到

我试图从一张来自“文档”的图像中找到水平线和垂直线。文档是从合同中扫描出来的页面,因此这些行看起来就像您在表或合同块中看到的一样

我一直在为这份工作尝试OpenCV。OpenCV中的Hough变换实现似乎对这项工作很有用,但我找不到任何参数组合,使它能够清晰地找到垂直线和水平线。我尝试了使用和不使用边缘检测。不走运。如果有人做过类似的事情,我很想知道怎么做

在这里可以看到我在OpenCV中使用HoughP进行实验前后的图像。这是我能做的最好的了

所以现在我想知道是否有另一种变换可以让我可靠地找到水平线和垂直线(最好是虚线)

我知道这个问题是可以解决的,因为我有Nuance和ABBYY OCR工具,可以可靠地提取水平线和垂直线,并返回线的边界框

谢谢!
Patrick.

您看过函数文档中的代码示例吗

我想你可以把它作为你算法的起点。要拾取水平线和垂直线,只需按线角度过滤掉其他线

更新:

正如我所见,你需要在页面上找到的不是线条而是水平和垂直边缘。对于此任务,您需要组合多个处理步骤以获得良好的结果

对于您的图像,我可以通过将Canny边缘检测与HoughLinesP相结合来获得良好的效果。下面是我的代码(我使用了python,但我想您已经看到了这个想法):

img=cv2.imread(“C:/temp/1.png”)
灰色=cv2.CVT颜色(img,cv2.COLOR\U BGR2GRAY)
边缘=cv2.Canny(灰色,80120)
线条=cv2.HoughLinesP(边,1,math.pi/2,2,无,30,1);
对于[0]行中的行:
pt1=(第[0]行,第[1]行)
pt2=(第[2]行,第[3]行)
cv2.线(img,pt1,pt2,(0,0255),3)
cv2.imwrite(“C:/temp/2.png”,img)
结果如下:


< P>你可以考虑离开霍夫线检测,因为这种方法寻找“全局”线,不一定是线段。我最近实现了一个识别“平行四边形”的应用程序——基本上是正方形,由于视角的原因,这些正方形可能会旋转,透视图可能会缩短。你可以考虑类似的事情。我的管道是:

  • 从RGB转换为灰度(CVTColor)
  • 平滑(cvSmooth)
  • 阈值(cvThreshold)
  • 检测边缘(cvCanny)
  • 查找等高线(cvFindContours)
  • 具有线性特征的近似轮廓(CVAPROXPOLY)
  • 在您的应用程序中,生成的轮廓列表可能会很大(取决于平滑的“积极性”和Canny边缘检测器的功能增强。您可以通过多种参数修剪此列表:轮廓查找器返回的点数、轮廓面积(cvContourArea)等。根据我的经验,我希望应用程序中的“有效”线具有定义良好的面积和顶点计数属性。此外,您可以根据端点之间的距离、连接端点的线定义的角度等过滤出轮廓


    根据CPU“时间”的多少,您始终可以将Hough算法与上述算法配对,以可靠地识别水平线和垂直线。

    如果您只需要“线”而不是“线段”,我会避免使用Canny、Hough、FindContours或任何其他类似的函数,以防您希望在代码中获得更高的速度。如果您的图像没有旋转,并且您希望查找的始终是垂直或水平的,我只会使用cv::Sobel(一个用于垂直,另一个用于水平)并为列和行创建累加数组。然后您可以在此类累加或配置文件中搜索最大值,例如通过设置阈值,您将知道其中有垂直或水平边缘线的行或列。

    不要将RGB转换为灰度。有时,RGB中的不同颜色可以合并到sa我的灰度值,所以它可能会错过一些轮廓。你应该分别分析每个RGB通道。

    这是一个使用形态学运算的完整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]
    

    检测到以绿色突出显示的水平线

    # 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)
    

    检测到以绿色突出显示的垂直线

    # 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)
    

    结果

    这是使用另一个输入图像的输出

    输入
    ->
    二进制
    ->
    检测到的水平
    ->
    检测到的垂直
    ->
    结果


    注意:根据图像的不同,您可能需要修改内核大小。例如,为了捕获更长的水平线,可能需要将水平内核从
    (40,1)
    增加到
    (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()
    

    您好,Andrey,谢谢。是的,我尝试了HoughLinesP,使用了许多不同的变量。我调整了我的原始问题,并添加了一个链接,指向我可以从HoughLinesP中获得的最佳图像。是的,我尝试了仅限于近水平线。Gre