OpenCV:比较差异很小的简单图像

Posted

技术标签:

【中文标题】OpenCV:比较差异很小的简单图像【英文标题】:OpenCV: comparing simple images with small difference 【发布时间】:2012-06-02 21:42:31 【问题描述】:

我有一堆“简单”的图像,我想比较它们是否相似。我使用模板匹配 (cv::matchTemplate) 将它们相互比较,结果非常好。

现在我想微调我的程序,但我遇到了一个问题。例如,我有两张看起来非常相似的图像。他们唯一的区别是另一个有更粗的线和项目的数字前面不同。当两幅图像都很小时,线条粗细的一个像素差异会在进行模板匹配时产生很大的结果差异。当线条粗细相同且唯一的区别是前面的数字时,匹配成功时,我会得到类似于0.98CV_TM_CCORR_NORMED 的模板匹配结果。当线条粗细不同时,匹配结果类似于 0.95。

我无法将阈值降低到 0.98 以下,因为其他一些类似的图像具有相同的线条粗细。

以下是示例图片:

那么我有什么选择呢?

我试过了:

扩大原件和模板 同时侵蚀两者 morphologyEx 两者 计算关键点并进行比较 寻找角落

但是还没有大的成功。这些图像是否过于简单以至于难以检测“好的特征”?

非常欢迎任何帮助。

谢谢!

编辑:

这里有一些其他示例图片。我的程序认为相似的内容放在同一个 zip 文件夹中。 ZIP

【问题讨论】:

这实际上取决于您的其他图像如何,您能否提供一些更独特的示例?可能您甚至不需要执行互相关,一个简单的距离测量就足够了。例如,对于这两个图像,使用归一化平方欧几里得距离我得到 ~0.44,而使用推土机距离我得到 ~0.02。通过一些基本的预处理,我得到 EMD 的 ~0 和前者的大约 0.27。问题是 EMD 可能会为您的所有图像返回值 ~0,具体取决于它们的方式——我不知道。 嘿,谢谢。我链接了一个包含其他图像的 zip 文件。我还没有尝试过 EMD。一定要试试。。 好的,但是错误分类是什么,所以我可以更好地理解问题?例如,图像 25.png 和 47.png 是否应该在同一个文件夹中?目前他们不是。图像图像 25.pgn 和 29.png 应该在不同的文件夹中吗?目前他们在同一个。 25 vs 47 在最佳情况下是的,它们应该在同一个文件夹中。它们是从不同的源图像中提取的,这就是它们如此不同的原因。是的,您理解正确,25 vs 28 vs 29。在那个文件夹中还有 54、55、56,它们与 25 相同,这四个应该在另一个文件夹中。 【参考方案1】:

一种可能的方法是细化两个图像,使每条线的宽度为一个像素,因为不同的粗细是导致相似度的主要问题。

该过程将首先对图像进行二值化/阈值化,然后对两个图像应用细化操作,因此现在两者的厚度相同,均为 1 px。然后使用您之前使用的常用模板匹配,效果很好。

如果您想了解更多关于二值图像的细化/骨架化的详细信息,这里有一些在各种讨论论坛和 OpenCV 群组上发布的 OpenCV 实现:

    OpenCV code for thinning(Guo 和 Hall 算法,适用于 CvMat 输入) The JR Parker implementation 使用 OpenCV 可能更高效的代码here(大量使用 OpenCV 优化的访问方法,但大部分页面都是日文的!) 最后是brief overview of thinning,以防您感兴趣。

【讨论】:

【参考方案2】:

你需要一些更基本的东西,没有太多理由去寻找花哨的方法。您的数字已经是二进制的,它们的形状总体上非常相似。

一个初步的想法:考虑某个图像中的上点和下点,并形成上壳和下壳(只是一个壳,而不是凸壳或其他任何东西)。如果给定列i,则该点被称为上点(即底点),它是从图像顶部(底部)开始的第一个点,而不是i 中的背景点。此外,您的图像主要是一个单一的连接组件(在某些情况下,垂直条分开,但这很好),因此您可以轻松丢弃小组件。这一步对您的情况很重要,因为我看到有些数字带有某种形式的噪声,与图像的其余部分无关。考虑到少于 100 个点的连接组件很小,这些是您为问题中包含的各个图像获得的外壳:

蓝线表示上层船体,绿线表示下层船体。如果不明显,当我们考虑这些船体的区域最大值和区域最小值时,我们会在它们中获得相同的数量。此外,除了y 轴上的一些位移外,它们都非常接近。如果我们考虑极值的平均x 位置并将两个图像的线绘制在一起,我们会得到下图。在这种情况下,蓝色和绿色的线条用于第二张图像,红色和青色的线条用于第一张图像。红点位于某些区域最小值的平均x 坐标中,蓝点相同,但区域最大值(这些是我们的兴趣点)。 (下图已调整大小以便更好地可视化)

如您所见,您无需执行任何操作即可获得许多几乎重叠的点。如果我们做得更少,即甚至不关心这种重叠,并继续以微不足道的方式对图像进行分类:如果图像a 和另一个图像b 在上层船体中具有相同数量的区域最大值,则上船体区域最小值相同,下船体区域最大值相同,底部船体区域最小值相同,则ab属于同一类。对所有图像执行此操作,所有图像都正确分组,但以下情况除外:

在这种情况下,第一个图像中的上层船体只有 3 个最大值和 3 个最小值,而第二个图像有 4 个最大值和 4 个最小值。接下来您会看到获得的船体和兴趣点的图:

您可以注意到,在第二个上层船体中,有两个非常接近的极值。平滑这条曲线消除了两个极值,使图像通过简单的方法匹配。另外,请注意,如果您在图像周围绘制一个矩形,那么此方法将告诉它们都是相等的。在这种情况下,您将需要比较多个船体,丢弃当前船体中的点并构建其他船体。尽管如此,这种方法能够正确地对所有图像进行分组,因为它们都非常简单且几乎没有噪音。

【讨论】:

感谢分析!你能指出我正确的方向吗?提取顶部和底部船体并计算每列的最大值和最小值的最佳方法是什么?我应该逐列还是在 OpenCV 中有一些现成的方法? OpenCV中有一个convexHull方法。也许我应该先试试。 @iiro 提取顶部和底部的船体,您可以按照答案中的描述简单地逐列进行,这是一种非常简单的方法。然后你可以在同一个y coord 中调整相邻点,我已经实现了这个,但它非常简单,我不依赖任何库(我认为没有人会实现它)。凸包与此处显示的非常不同,但也许可以使用它并以不同的方式进行分析。 @iiro 只记得一件事:这可以通过 hit-or-miss 转换轻松完成。但这在 OpenCV 中不可用,因此您必须自己实现该部分(同样,这非常容易)。【参考方案3】:

据我所知,困难在于形状相同,只是尺寸不同。一个简单的破解方法可能是: - 减去图像,然后侵蚀。如果形状相同但稍大一点,则减去将只留下边缘,边缘会变薄并消失,并作为噪声侵蚀。

更正式一点,是先获取轮廓,然后是近似多边形并进行不变量比较(Hu Moments 等)

【讨论】:

以上是关于OpenCV:比较差异很小的简单图像的主要内容,如果未能解决你的问题,请参考以下文章

使用 OpenCV 的视角和光照条件略有不同的两张图像之间的差异

使用 OpenCV Python 检测和可视化两个图像之间的差异

2D 卷积 - 与 opencv 的输出相比,结果错误

opencv-python图像处理 ----图像梯度Sobel算子

使用Opencv构建一个简单的图像相似检测器(MSESSIM)

OPENCV怎么能在比较复杂的图像中找到想要的物体的轮廓呢