如果阈值不够好,如何检测 opencv (c++) 中的异常?
How to detect anomalies in opencv (c++) if threshold is not good enought?
我有这样的灰度图像:
我想检测此类图像的异常情况。在第一张图片(左上角)上我想检测三个点,在第二张图片(右上角)上有一个小点和一个 "Foggy area"(在右下角),在最后一张图片上,图像中间某处还有一个小点。
普通的静态阈值处理对我来说效果不佳,而且 Otsu 的方法始终是最佳选择。有没有更好、更强大或更智能的方法来检测这样的异常情况?在 Matlab 中,我使用了 Frangi Filtering(特征值过滤)之类的东西。任何人都可以建议好的处理算法来解决这样的表面异常检测吗?
编辑:添加了另一张带有明显异常的图像:
使用@Tapio 的顶帽过滤和对比度调整。
由于 @Tapio 为我们提供了如何增加表面异常对比度的好主意,就像我一开始问的那样,我向大家提供了一些我的结果。我有这样的图像:
这是我如何使用顶帽过滤和对比度调整的代码:
kernel = getStructuringElement(MORPH_ELLIPSE, Size(3, 3), Point(0, 0));
morphologyEx(inputImage, imgFiltered, MORPH_TOPHAT, kernel, Point(0, 0), 3);
imgAdjusted = imgFiltered * 7.2;
结果在这里:
还有一个问题是如何从最后一张图片中分割异常??因此,如果有人知道如何解决它,那就接受吧! :) ??
@skoda23,我会尝试使用模糊部分的微调参数进行锐化掩蔽,以便强调高频并彻底测试它,以便在此过程中不会丢失任何重要信息。请记住,期望计算机完成超人的工作通常不是一个好主意。如果人类怀疑异常在哪里,计算机将不得不这样做。因此,首先对图像进行预处理很重要,这样异常现象对于人眼来说是显而易见的。不锐化掩蔽(或添加)的替代方法可能是 CLAHE。但同样:请记住非常小心地微调它 - 它可能会过多地显示电路板的纹理并干扰您的任务。
基本阈值或 Otsu 的替代方法是 AdaptiveThreshold()
这可能是个好主意,因为您要查找的不同区域之间的强度值存在差异。
我的第二个猜测是首先对最暗的点使用固定值阈值,然后尝试 Sobel 或 Canny。应该存在一个最佳邻域,其中棋盘的纹理不会像异常一样发光。您也可以尝试在边缘检测之前进行模糊处理(如果您已通过阈值检测到小缺陷)。
再说一次:在这种方法的每一步进行大量实验对于任务来说至关重要,因为微调参数对于最终的成功至关重要。我建议与 the trackbar 交朋友,以加快进程。祝你好运!
你基本上是在处理一个不幸的事实,即现实是模拟的。阈值是一种将模拟范围转换为离散(二进制)范围的方法。 任何 阈值都可以做到这一点。那么 "good enough" 阈值到底是什么意思?
让我们暂时搁置这个想法。我看到很多异常现象——有点像细灰色蠕虫。显然,你忽略了它们。我正在应用与您不同的阈值。这可能是合理的,但您正在应用我没有的领域知识。
我怀疑这些灰色蠕虫会破坏您的固定值阈值。这并不是说固定阈值的想法不好。您可以使用它来查找 一些 工件并排除它们。会遗漏一些暗色块,但可以通过使用大于这些蠕虫宽度的邻域大小将每个像素替换为其邻域的中值来带出。在黑暗的补丁中,这几乎没有作用,但它消除了小的局部变化。
我不假装这两种类型的异常是仅有的两种,但这确实是一个应用程序领域的问题,而不是技术问题。例如。您似乎没有灯光伪影(反射),至少在这 3 个样本中没有。
你应该看看底帽过滤。它被定义为原始图像和图像的形态闭合之间的差异,它使小细节(例如您正在寻找的细节)变得耀眼。
我调整了对比度,使两个图像都可见。在查看强度时,异常更加明显,并且更容易分割。
我们来看第一张图:
由于我使用的可视化工具造成的缩放,直方图值并不代表真实情况。但是相对距离确实如此。所以现在阈值范围更大了,目标从 window 变成了谷仓门。
全局阈值(强度 > 15):
Otsu 的方法在这里效果不佳。它将所有小细节分割到前景。
形态学开运算去噪后:
我还假设黑点是您感兴趣的异常。通过将阈值设置得较低,您可以包含更多的表面细节。例如,第三张图片在我看来没有任何特别有趣的特征,但这供您判断。就像 m3h0w 所说的那样,知道如果您的眼睛难以判断某些东西对于计算机来说可能是不可能的,这是一个很好的启发式方法。
我有这样的灰度图像:
普通的静态阈值处理对我来说效果不佳,而且 Otsu 的方法始终是最佳选择。有没有更好、更强大或更智能的方法来检测这样的异常情况?在 Matlab 中,我使用了 Frangi Filtering(特征值过滤)之类的东西。任何人都可以建议好的处理算法来解决这样的表面异常检测吗?
编辑:添加了另一张带有明显异常的图像:
使用@Tapio 的顶帽过滤和对比度调整。
由于 @Tapio 为我们提供了如何增加表面异常对比度的好主意,就像我一开始问的那样,我向大家提供了一些我的结果。我有这样的图像:
这是我如何使用顶帽过滤和对比度调整的代码:
kernel = getStructuringElement(MORPH_ELLIPSE, Size(3, 3), Point(0, 0));
morphologyEx(inputImage, imgFiltered, MORPH_TOPHAT, kernel, Point(0, 0), 3);
imgAdjusted = imgFiltered * 7.2;
结果在这里:
还有一个问题是如何从最后一张图片中分割异常??因此,如果有人知道如何解决它,那就接受吧! :) ??
@skoda23,我会尝试使用模糊部分的微调参数进行锐化掩蔽,以便强调高频并彻底测试它,以便在此过程中不会丢失任何重要信息。请记住,期望计算机完成超人的工作通常不是一个好主意。如果人类怀疑异常在哪里,计算机将不得不这样做。因此,首先对图像进行预处理很重要,这样异常现象对于人眼来说是显而易见的。不锐化掩蔽(或添加)的替代方法可能是 CLAHE。但同样:请记住非常小心地微调它 - 它可能会过多地显示电路板的纹理并干扰您的任务。
基本阈值或 Otsu 的替代方法是 AdaptiveThreshold()
这可能是个好主意,因为您要查找的不同区域之间的强度值存在差异。
我的第二个猜测是首先对最暗的点使用固定值阈值,然后尝试 Sobel 或 Canny。应该存在一个最佳邻域,其中棋盘的纹理不会像异常一样发光。您也可以尝试在边缘检测之前进行模糊处理(如果您已通过阈值检测到小缺陷)。
再说一次:在这种方法的每一步进行大量实验对于任务来说至关重要,因为微调参数对于最终的成功至关重要。我建议与 the trackbar 交朋友,以加快进程。祝你好运!
你基本上是在处理一个不幸的事实,即现实是模拟的。阈值是一种将模拟范围转换为离散(二进制)范围的方法。 任何 阈值都可以做到这一点。那么 "good enough" 阈值到底是什么意思?
让我们暂时搁置这个想法。我看到很多异常现象——有点像细灰色蠕虫。显然,你忽略了它们。我正在应用与您不同的阈值。这可能是合理的,但您正在应用我没有的领域知识。
我怀疑这些灰色蠕虫会破坏您的固定值阈值。这并不是说固定阈值的想法不好。您可以使用它来查找 一些 工件并排除它们。会遗漏一些暗色块,但可以通过使用大于这些蠕虫宽度的邻域大小将每个像素替换为其邻域的中值来带出。在黑暗的补丁中,这几乎没有作用,但它消除了小的局部变化。
我不假装这两种类型的异常是仅有的两种,但这确实是一个应用程序领域的问题,而不是技术问题。例如。您似乎没有灯光伪影(反射),至少在这 3 个样本中没有。
你应该看看底帽过滤。它被定义为原始图像和图像的形态闭合之间的差异,它使小细节(例如您正在寻找的细节)变得耀眼。
我调整了对比度,使两个图像都可见。在查看强度时,异常更加明显,并且更容易分割。
我们来看第一张图:
由于我使用的可视化工具造成的缩放,直方图值并不代表真实情况。但是相对距离确实如此。所以现在阈值范围更大了,目标从 window 变成了谷仓门。
全局阈值(强度 > 15):
Otsu 的方法在这里效果不佳。它将所有小细节分割到前景。
形态学开运算去噪后:
我还假设黑点是您感兴趣的异常。通过将阈值设置得较低,您可以包含更多的表面细节。例如,第三张图片在我看来没有任何特别有趣的特征,但这供您判断。就像 m3h0w 所说的那样,知道如果您的眼睛难以判断某些东西对于计算机来说可能是不可能的,这是一个很好的启发式方法。