使用OpenCV在彩色背景上的边缘检测

时间:2017-12-20 05:06:34

标签: android opencv edge-detection

我正在使用以下代码来检测给定文档的边缘。

private Mat edgeDetection(Mat src) {
    Mat edges = new Mat();
    Imgproc.cvtColor(src, edges, Imgproc.COLOR_BGR2GRAY);
    Imgproc.GaussianBlur(edges, edges, new Size(5, 5), 0);
    Imgproc.Canny(edges, edges, 10, 30);
    return edges;
}

然后我可以通过查找此中最大的轮廓来找到此edges中的文档。

我的问题是我可以从以下图片中找到该文件:

enter image description here

但不是来自以下图片:

enter image description here

如何改善此边缘检测?

2 个答案:

答案 0 :(得分:10)

我使用的是Python,但主要思路是一样的。

如果你直接做cvtColor:bgr - >灰色的img2,然后你必须失败。因为灰色难以区分区域:

enter image description here

相关答案:

  1. How to detect colored patches in an image using OpenCV?
  2. Edge detection on colored background using OpenCV
  3. OpenCV C++/Obj-C: Detecting a sheet of paper / Square Detection
  4. 在您的图片中,论文为white,背景为colored。因此,最好在Saturation(饱和度)中检测论文是HSV color space频道。对于HSV,请参阅https://en.wikipedia.org/wiki/HSL_and_HSV#Saturation

    主要步骤:

    1. 阅读BGR
    2. 将图片从bgr转换为hsv空间
    3. 阈值S通道
    4. 然后找到最大外部轮廓(或根据需要CannyHoughLines,我选择findContours),大约找到角落。
    5. 这是第一个结果:

      enter image description here

      这是第二个结果:

      enter image description here

      Python代码(Python 3.5 + OpenCV 3.3):

      #!/usr/bin/python3
      # 2017.12.20 10:47:28 CST
      # 2017.12.20 11:29:30 CST
      
      import cv2
      import numpy as np
      
      ##(1) read into  bgr-space
      img = cv2.imread("test2.jpg")
      
      ##(2) convert to hsv-space, then split the channels
      hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
      h,s,v = cv2.split(hsv)
      
      ##(3) threshold the S channel using adaptive method(`THRESH_OTSU`) or fixed thresh
      th, threshed = cv2.threshold(s, 50, 255, cv2.THRESH_BINARY_INV)
      
      ##(4) find all the external contours on the threshed S
      cnts = cv2.findContours(threshed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2]
      canvas  = img.copy()
      #cv2.drawContours(canvas, cnts, -1, (0,255,0), 1)
      
      ## sort and choose the largest contour
      cnts = sorted(cnts, key = cv2.contourArea)
      cnt = cnts[-1]
      
      ## approx the contour, so the get the corner points
      arclen = cv2.arcLength(cnt, True)
      approx = cv2.approxPolyDP(cnt, 0.02* arclen, True)
      cv2.drawContours(canvas, [cnt], -1, (255,0,0), 1, cv2.LINE_AA)
      cv2.drawContours(canvas, [approx], -1, (0, 0, 255), 1, cv2.LINE_AA)
      
      ## Ok, you can see the result as tag(6)
      cv2.imwrite("detected.png", canvas)
      

答案 1 :(得分:1)

在OpenCV中有一个名为dilate的功能,这会使线条变暗。所以尝试下面的代码。

private Mat edgeDetection(Mat src) {
    Mat edges = new Mat();
    Imgproc.cvtColor(src, edges, Imgproc.COLOR_BGR2GRAY);
    Imgproc.dilate(edges, edges, Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(10, 10)));
    Imgproc.GaussianBlur(edges, edges, new Size(5, 5), 0);
    Imgproc.Canny(edges, edges, 15, 15 * 3);
    return edges;
}