OpenCV - canny边缘检测不能正常工作

4

我是一个OpenCV在Android中的新手。目前,我正在开发一个文档检测演示应用程序。我迄今为止所做的工作如下:

原始图像 -> 灰度图像 -> GaussianBlur -> Canny边缘检测 -> 查找轮廓 -> 绘制轮廓

我能够完美地检测出纸张,正如您在下面的图像中所看到的。

enter image description here

但它不能检测出一些文档。以下是其中之一:

enter image description here

我对此进行了大量研究,并发现问题出在Canny边缘检测上。以下是Canny图像:

enter image description here

如您所看到的,边缘检测不是完美地链接,并且在某些点上它没有连接边缘。这就是问题所在。

我遇到了类似的问题: 如何选择在OpenCV中实现的Canny边缘检测算法的最佳参数集? 我遵循了该解决方案,但它对我没有起作用。

我的Canny检测代码如下:

double otsu_thresold = Imgproc.threshold(mGray,edged,0,255, Imgproc.THRESH_OTSU);
Imgproc.Canny(mRgba, edged, otsu_thresold*0.5,otsu_thresold);

我不知道我错在哪里!该怎么做才能完美地检测文档?

1
为了增强边缘,使用形态学膨胀。请参阅此页面 - Jeru Luke
@ChristophRackwitz 我决定停止进行这样的编辑,因为它会用旧内容淹没活跃页面。根据另一个SO用户的建议收到:https://stackoverflow.com/questions/44656890/measure-velocity-of-objects-in-a-video?noredirect=1#comment130031580_44656890 - Jeru Luke
2个回答

10
首先,执行Canny边缘检测的方法需要改变。您手动设置了cv2.Canny()中的较低和较高阈值。您可以自动完成此操作。我使用 THIS LINK作为参考。
请使用以下代码片段:
v = np.median(gray_image)

#---- apply automatic Canny edge detection using the computed median----
lower = int(max(0, (1.0 - sigma) * v))
upper = int(min(255, (1.0 + sigma) * v))
edged = cv2.Canny(gray_image, lower, upper)
cv2.imshow('Edges',edged)

那么我在这里做什么?

我正在获取灰度图像的中位数值。选择sigma值为0.33以设置lowerupper阈值。统计学家通常使用0.33值进行数据科学,因此在这里也被考虑。

这就是我得到的结果:

enter image description here

为了增强这些边缘信息,我使用了cv2.MORPH_CROSS内核进行形态膨胀处理:morphological dilation

enter image description here

现在只需执行通常的cv2.findContours()操作并绘制最大轮廓。

:)


我正在使用大津法动态查找阈值。我也尝试了您的解决方案,但它没有起作用,并且还降低了相机帧速率。 - ImLearning
不,我的意思是由于阈值计算,相机预览帧变慢了。 - ImLearning
这可能是因为它正在计算图像的中位数并根据该值设置阈值。 - Jeru Luke
是的,这会降低相机预览的性能。顺便说一句,非常感谢你的努力。你有其他解决方案吗? - ImLearning
你的问题是关于更好的边缘检测机制,所以我回答了它。对于它如何降低性能,我一点都不知道。 - Jeru Luke
显示剩余2条评论

3

我对Jeru Luke发布的算法进行了小的改进,取得了更好的结果。

在文档检测中,我们更倾向于搜索文档的黑暗阴影边缘:

  • 对于亮色图像,如白纸,中位数较高,“255 - median”比仅使用中位数效果更好
  • 对于小值,sigma值太小,不能产生足够宽的范围。

这是我的C#算法:

    double s = 0.33;
    if (imageMedian > 191) // light images
    {
      cannyTh1 = (int)Math.Max(0, (1 - 2*s) * (255 - imageMedian));
      cannyTh2 = (int)Math.Max(85, (1 + 2*s) * (255 - imageMedian));
    }
    else if (imageMedian > 127)
    {
      cannyTh1 = (int)Math.Max(0, (1 - s) * (255 - imageMedian));
      cannyTh2 = (int)Math.Min(255, (1 + s) * (255 - imageMedian));
    }
    else if (imageMedian < 63) // dark images
    {
      cannyTh1 = (int)Math.Max(0, (1 - 2*s) * imageMedian);
      cannyTh2 = (int)Math.Max(85, (1 + 2*s) * imageMedian);
    }
    else
    {
      cannyTh1 = (int)Math.Max(0, (1 - s) * imageMedian);
      cannyTh2 = (int)Math.Min(255, (1 + s) * imageMedian);
    }

此外,对于一些文档,可以通过以下方法改进结果:
  • 在使用中值滤波器后,对图像进行清晰化处理
  • 使用更强的中值滤波器
  • 针对图像的不同部分计算中值并执行Canny滤波器,因为阴影和光照对图像各个部分的影响可能大不相同。

感谢您的努力,但我已经不再参与这个项目了,我会检查您的解决方案并稍后回复您。 - ImLearning

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