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=100
和high=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% 水平/未旋转的线的主要内容,如果未能解决你的问题,请参考以下文章