首页 > 解决方案 > Canny 边缘检测未检测到 100% 水平/未旋转的线

问题描述

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

这些是输入图像:

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

纯水平线,输入图像 水平线旋转 1°,输入图像

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

纯水平线,输出图像 水平线旋转 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 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 函数使用的 Gy 矩阵的零行引起的(在 Canny 函数文章中提到过)。

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


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

这是我们的输入图像:

带光栅的渐变(裁剪预览)

(为更漂亮的帖子裁剪和调整大小,下载原版。)

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 都无法检测到边缘

标签: javaopencvedge-detectioncanny-operator

解决方案


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

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


推荐阅读