使用OpenCV对彩色背景进行边缘检测

7

我正在使用以下代码从给定的文档中检测边缘:

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个回答

12

我使用Python,但主要思路相同。

如果您直接对img2进行cvtColor:bgr-> gray,则必定失败。因为灰度难以区分区域:

enter image description here


相关答案:

  1. 如何使用OpenCV检测图像中的彩色补丁?
  2. 在带颜色背景的图像上使用OpenCV进行边缘检测
  3. OpenCV C++/Obj-C:检测一张纸/方形检测

在您的图像中,纸张是白色,而背景是彩色。因此,最好在HSV color space中检测纸张的Saturation(饱和度)通道。关于HSV,请参见https://en.wikipedia.org/wiki/HSL_and_HSV#Saturation


主要步骤:

  1. 读入BGR
  2. 将图像从bgr转换为hsv空间
  3. 阈值S通道
  4. 然后找到最大的外部轮廓(或者按照您喜欢的方式进行CannyHoughLines,我选择findContours),近似得到角落。

这是第一次结果:

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)

请问您能解释一下这行代码中的 ththreshold 是什么意思吗?代码如下:th, threshed = cv2.threshold(s, 50, 255, cv2.THRESH_BINARY_INV)。我正在尝试将您的代码转换并在C++中测试,但不知道如何处理这一行代码。我查了一下,发现 threshold 函数只有一个 double 输出,但是您好像得到了两个输出(虽然我不懂 Python,只是猜测)。 - Hasani
2
@Hasani th 是返回的阈值;threshed 是二值化后的图像。函数原型:cv2.threshold(src, thresh, maxval, type[, dst]) -> retval, dst - Kinght 金

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;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接