Canny 边缘检测未检测到 100% 水平/未旋转的线

Posted

技术标签:

【中文标题】Canny 边缘检测未检测到 100% 水平/未旋转的线【英文标题】:Canny edge detection does not detect 100% horizontal/un-rotated lines 【发布时间】:2019-11-15 20:18:17 【问题描述】:

Canny 边缘检测是否应该检测纯的、非旋转的水平线?

这些是输入图像:

左: 100% 水平(非旋转)非模糊线条右:同一图像旋转 1°

相应的输出“边缘”图像:

(为了更好地判断,图像在此处缩放了 2 倍,没有进行平滑处理。)

使用阈值 low=250x0.66 和 high=250x1.33 以及内核大小 k=3 处理图像。

虽然梯形图像产生了令人满意的结果,但之前的图像却没有。

图像目前没有进一步预处理,你看到的就是进入 Canny 的内容。

我创建了第一张图片作为测试数据。它可能是一个构造的案例,尽管这样的线条可能会出现在现实世界的场景中。

MCVE:

public class q58884116 
    public static void main(String[] args) throws Exception 
        System.load(new File(Paths.get("target", "classes", "libopencv_java412.so").toString()).getAbsolutePath());

        File inFile = new File(args[0]);
        File outFile = new File(args[1]);

        Mat imageColor = Imgcodecs.imread(inFile.getAbsolutePath(), Imgcodecs.IMREAD_COLOR);
        Mat patternProbeImage = new Mat();
        Imgproc.cvtColor(imageColor, patternProbeImage, Imgproc.COLOR_BGR2GRAY);

        Mat edges = new Mat();
        // Value determined from histogram in Gimp.
        Imgproc.Canny(patternProbeImage, edges, 250 * 0.66, 250 * 1.33, 3, true);

        Imgcodecs.imwrite(outFile.getAbsolutePath(), edges);
    

输入图像(未缩放):input.png

从 Git 编译 OpenCV 4.1.2 cmake 3.7.2 GCC 6.3.0 openjdk 1.8.0_232 使用 Java 库。

构建步骤:

$ git clone https://github.com/opencv/opencv.git
$ cd opencv/
$ git checkout 4.1.2
$ cd cmake/
$ cmake -DCMAKE_INSTALL_PREFIX="/opt/opencv" ..
$ make -j4
$ make install

我必须承认,我不熟悉 Canny 背后的理论,甚至不熟悉计算机视觉。我刚刚开始使用它。虽然我可以想象这可能是由Sobel function(在Canny函数文章中提到的)使用的Gy矩阵的零行引起的。

如果这确实是 Canny 的限制,那么处理这种情况的常用方法是什么(简而言之)?


我根据经验处理了这个问题:我创建了一个从白色到黑色的渐变图像 上面有一个黑色的光栅图案。光栅应代表 原始测试图像在不同背景上的线条。

这是我们的输入图像:

(为更漂亮的帖子裁剪和调整大小,download original。)

MCVE 被扩展为生成各种阈值范围的边缘(不是 每种可能的组合都有,但数量相当):

for (int i = 0; i < 255 - 50; i++) 
    Mat edges = new Mat();
    Imgproc.Canny(patternProbeImage, edges, i, i + 50, 3, true);

    Imgcodecs.imwrite(getOutputFile(outFile, "lb-0-" + String.format("%03d", i)).getAbsolutePath(), edges);

然后我们可以检查生成的边缘。

使用这一衬里,生成所有图像的马赛克(精灵),以便更轻松地生成 检查:

$ convert gradient-grating.out.lb-0-*.png +append  gradient-grating.out.lb.png

这是结果:

正如我们所见,Canny 无法在最小值上检测到越来越多的边缘 价值侧(顶部)随着较低阈值的增加而增加。我预料到了这一点。尽管在最大值方面,Canny 永远无法检测到边缘,无论给定什么阈值。

【问题讨论】:

Canny 主要用于边缘检测,通过确定图像的亮度发生剧烈变化的位置。它用于提取图像中对象的结构。本质上,计算机视觉的优势是像素的突然变化。这可能是由于您的阈值。我用low=100high=200 得到了正确的结果。检测线条的替代方法是使用HoughLinesP 或构建水平内核并使用形态学 我刚刚在 Python 中尝试过,它成功了。以前,我在 Java 中使用过 OpenCV,我发现 Canny 过滤器在 OpenCV/Python 中的行为方式与在 OpenCV/Java 中的不同。 斯蒂芬的宝贵意见。 nathancy,我之前和现在都用你的价值观尝试过其他阈值 - 没有成功。 使用我的 Java Opencv(3.3 版)我得到了两个图像的相似输出,虽然它们不如第二个图像的输出好,但绝对比第一个好。使用我的 c++ Opencv(4.0 版),我的结果与您的相同。我想知道@StephenMeschke 测试的版本是什么。我稍后会进一步调查。 高阈值250 x 1.66超出灰度范围有什么意义? 【参考方案1】:

尝试保存图像,然后直接打开图像文件。这可能只是绘图仪如何渲染图像的问题。

我自己也有同样的问题,但解决了。我正在使用 matplotlib 通过 jupyter 笔记本查看我的边缘图像。 100% 水平边缘在笔记本内显示时不会呈现。但是当我将它保存为png并直接打开图像文件时,水平边缘实际上是存在的。

【讨论】:

以上是关于Canny 边缘检测未检测到 100% 水平/未旋转的线的主要内容,如果未能解决你的问题,请参考以下文章

Canny 边缘检测器未处理的异常

OpenCV Canny边缘检测 | 图像轮廓检测 | 直方图均衡化

OpenCv之Canny边界检测(笔记13)

sobel边缘检测优缺点与canny算子的优缺点?

自适应 Canny 边缘检测

Canny边缘检测算法的步骤和理解