【问题标题】:Removing long horizontal/vertical lines from edge image using OpenCV使用 OpenCV 从边缘图像中删除长的水平/垂直线
【发布时间】:2013-10-06 08:11:22
【问题描述】:

如何使用标准图像处理过滤器(来自 OpenCV)从图像中去除长的水平和垂直线?

图像是黑白的,因此删除意味着简单地涂黑。

插图:

我目前正在 Python 中执行此操作,迭代像素行和列并检测连续像素的范围,删除那些长于 N 像素的像素。但是,与 OpenCV 库相比,它确实很慢,如果有办法用 OpenCV 函数完成同样的任务,那可能会快几个数量级。

我想这可以通过使用一行像素(对于水平线)的内核进行卷积来完成,但我很难确定可以解决问题的确切操作。

【问题讨论】:

  • 这里只是快速思考。你为什么不使用霍夫线检测来查找线并在你选择的线上做你想做的事?
  • 是的,如果需要,请查看the docstheory
  • 似乎返回的长线段被分解成许多小线段,这破坏了过滤掉不够长线段的能力......知道为什么会发生这种情况吗?

标签: opencv image-processing


【解决方案1】:

“长”有多长。长,例如,贯穿整个图像长度的线条,还是比n 像素长?

如果是后者,那么您只需使用n+1 X n+1 中值或众数滤波器,并将角系数设置为零,即可获得所需的效果。

如果您仅指的是整个图像宽度的线条,只需对一行数据使用memcmp() 函数,并将其与预分配的零数组进行比较,该数组的长度与一排。如果它们相同,则您知道您有一个跨越图像水平长度的空白行,并且可以删除该行。

这将比您当前使用的元素比较快得多,并且在这里得到了很好的解释:

Why is memcpy() and memmove() faster than pointer increments?

如果要对垂直线重复相同的操作,只需将图像转置,然后重复操作即可。

我知道这更像是一种系统优化级别的方法,而不是您要求的 openCV 过滤器,但它可以快速安全地完成工作。如果您设法强制图像和空数组在内存中 32 位对齐,则可以进一步加快计算速度。

【讨论】:

    【解决方案2】:

    如果你的线条真的是水平/垂直的,试试这个

    import cv2
    import numpy as np
    img = cv2.imread('c:/data/test.png')
    gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    linek = np.zeros((11,11),dtype=np.uint8)
    linek[5,...]=1
    x=cv2.morphologyEx(gray, cv2.MORPH_OPEN, linek ,iterations=1)
    gray-=x
    cv2.imshow('gray',gray)
    cv2.waitKey(0)    
    

    结果

    您可以参考OpenCV Morphological Transformations 文档了解更多详细信息。

    【讨论】:

    • 有人可以向 python-ignorant 解释 linek = np.zeros((11,11),dtype=np.uint8) linek[5,...]=1 的作用吗?首选 C++ ;~)
    • Mat linek=Mat::zeros(Size(11,11),CV_8UC1);linek.row(5)=255;
    • 这有助于删除水平线...我需要进行哪些更改才能删除垂直线?
    • 只需添加linek[...,5]=1 基本上创建一个+ 形状的内核
    【解决方案3】:

    要从图像中删除水平线,您可以使用边缘检测算法来检测边缘,然后使用 OpenCV 中的 Hough 变换来检测线并将它们着色为白色:

    import cv2
    import numpy as np
    img = cv2.imread(img,0)
    laplacian = cv2.Laplacian(img,cv2.CV_8UC1) # Laplacian Edge Detection
    minLineLength = 900
    maxLineGap = 100
    lines = cv2.HoughLinesP(laplacian,1,np.pi/180,100,minLineLength,maxLineGap)
    for line in lines:
        for x1,y1,x2,y2 in line:
            cv2.line(img,(x1,y1),(x2,y2),(255,255,255),1)
    cv2.imwrite('Written_Back_Results.jpg',img)
    

    【讨论】:

      【解决方案4】:

      这是给 javacv 的。

      包 com.test11;

      import org.opencv.core.*;
      import org.opencv.imgproc.Imgproc;
      import org.opencv.imgcodecs.Imgcodecs;
      
      public class GetVerticalOrHorizonalLines {
      
          static{ System.loadLibrary(Core.NATIVE_LIBRARY_NAME); }
      
          public static void main(String[] args) {
      
              //Canny process before HoughLine Recognition
      
              Mat source = Imgcodecs.imread("src//data//bill.jpg");
              Mat gray = new Mat(source.rows(),source.cols(),CvType.CV_8UC1);
              Imgproc.cvtColor(source, gray, Imgproc.COLOR_BGR2GRAY);
      
              Mat binary = new Mat();
              Imgproc.adaptiveThreshold(gray, binary, 255, Imgproc.ADAPTIVE_THRESH_MEAN_C, Imgproc.THRESH_BINARY, 15, -2);
              Imgcodecs.imwrite("src//data//binary.jpg", binary);
      
              Mat horizontal = binary.clone();
              int horizontalsize = horizontal.cols() / 30;
              int verticalsize = horizontal.rows() / 30;
      
              Mat horizontal_element = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(horizontalsize,1));
              //Mat element = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(3,3));
              Imgcodecs.imwrite("src//data//horizontal_element.jpg", horizontal_element);
      
              Mat Linek = Mat.zeros(source.size(), CvType.CV_8UC1);
              //x =  Imgproc.morphologyEx(gray, dst, op, kernel, anchor, iterations);
              Imgproc.morphologyEx(gray, Linek,Imgproc.MORPH_BLACKHAT, horizontal_element);
              Imgcodecs.imwrite("src//data//bill_RECT_Blackhat.jpg", Linek);
      
              Mat vertical_element = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(1,verticalsize));
              Imgcodecs.imwrite("src//data//vertical_element.jpg", vertical_element);
      
              Mat Linek2 = Mat.zeros(source.size(), CvType.CV_8UC1);
              //x =  Imgproc.morphologyEx(gray, dst, op, kernel, anchor, iterations);
              Imgproc.morphologyEx(gray, Linek2,Imgproc.MORPH_CLOSE, vertical_element);
              Imgcodecs.imwrite("src//data//bill_RECT_Blackhat2.jpg", Linek2);
      
                  }
          }
      

      【讨论】:

      • 第一个,可以同时去除一张图片中的竖线和横线。第二种,可以分别去掉一张图片中的竖线和横线,即得到一张没有竖线或者没有横线的图片。
      • @goto 如果你没有检查我的代码,你为什么点击不喜欢?
      【解决方案5】:

      另一个。

      package com.test12;
      
      import org.opencv.core.*;
      import org.opencv.imgproc.Imgproc;
      import org.opencv.imgcodecs.Imgcodecs;
      
      public class ImageSubstrate {
      
          static{ System.loadLibrary(Core.NATIVE_LIBRARY_NAME); }
      
          public static void main(String[] args) {
      
                 Mat source = Imgcodecs.imread("src//data//bill.jpg");
      
                 Mat image_h = Mat.zeros(source.size(), CvType.CV_8UC1);
                 Mat image_v = Mat.zeros(source.size(), CvType.CV_8UC1); 
      
                 Mat output = new Mat();
                 Core.bitwise_not(source, output);
                 Mat output_result = new Mat();
      
                 Mat kernel_h = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(20, 1));
                 Imgproc.morphologyEx(output, image_h, Imgproc.MORPH_OPEN, kernel_h);
                 Imgcodecs.imwrite("src//data//output.jpg", output);  
      
                 Core.subtract(output, image_h, output_result);
                 Imgcodecs.imwrite("src//data//output_result.jpg", output_result);    
      
      
                 Mat kernel_v = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(1, 20));   
                 Imgproc.morphologyEx(output_result, image_v, Imgproc.MORPH_OPEN, kernel_v);
                 Mat output_result2 = new Mat();
      
                 Core.subtract(output_result, image_v, output_result2);          
                 Imgcodecs.imwrite("src//data//output_result2.jpg", output_result2);
          }
      }
      

      【讨论】: