find高质量和低质量,像素化图像之间的匹配 – 有可能吗? 怎么样?

我有个问题。 我的公司给了我一个非常无聊的任务。 我们有两个对话框的数据库。 其中一个数据库包含可怕的质量图像,另一个质量很高。

不幸的是,可怕的质量对话包含其他信息的重要映射。

我一直负责手动处理所有不好的图像,并将它们匹配到良好的图像。

是否有可能在任何程度上自动化这个过程? 以下是两个对话框(从Google图像中随机抽取)的示例:

良好的图像质量

质量差的形象

所以我现在正在用C#编写一个程序,把这些照片从数据库中拉出来,循环遍历它们,find具有相同形状的照片,然后返回它们的ID。 我最好的select是什么?

我真的没有理由为此使用任何外部库,我已经做了很多次这样的事情,下面的algorithm工作得很好。 我假设如果你比较两个尺寸相同的图像,但是如果它们没有相同的尺寸,你可以调整一个尺寸。

badness := 0.0 For x, y over the entire image: r, g, b := color at x,y in image 1 R, G, B := color at x,y in image 2 badness += (rR)*(rR) + (gG)*(gG) + (bB)*(bB) badness /= (image width) * (image height) 

现在,在两幅图像之间已经有了一个标准化的坏点值,坏点越低,图像匹配的可能性就越大。 这是简单而有效的,在某些情况下,有各种各样的事情可以使它工作得更好或更快,但是你可能不需要这样的事情。 你甚至不需要正常化坏处,但是如果你想手动查看几个可能的匹配,这样你就可以为它设置一个门槛。


由于这个问题已经得到了更多的关注,我决定添加一个方法来加速处理多次的图像。 当我有成千上万的图像需要比较时,我使用了这种方法,我确信一对典型的图像会有很大的不同。 我也知道,我所有的图像都是完全一样的尺寸。 在你比较对话框的情况下,你的典型图像可能大多是灰色的,而你的一些图像可能需要resize(虽然也许这只是表示不匹配),在这种情况下,这种方法可能不会让你许多。

这个想法是形成一个四叉树 ,其中每个节点代表节点代表的区域的平均RGB值。 因此,一个4×4的图像将有一个RGB值等于图像的平均RGB值的根节点,其子元素将具有代表它们各自的2×2区域的平均RGB值的RGB值,并且它们的子元素将代表单个像素。 (在实践中,不要深入到大约16×16的区域,此时您应该开始比较单个像素。)

在开始比较图像之前,您还需要确定不良阈值。 你不会用任何可靠的准确性来计算高于这个阈值的坏点,所以这基本上是你愿意把图像标记为“不匹配”的阈值。

现在,当你比较图像A到图像B时,首先比较它们的四叉树表示的根节点。 像计算单个像素图像一样计算不良情况,如果不良情况超过阈值,则立即返回,并在此级别报告不良情况。 因为你使用的是规范化的坏点,而坏点是用平方差来计算的,所以在任何特定级别上的坏处都会等于或低于下级的坏处,所以如果超过了任何一点的阈值,在个别像素级别的阈值。

如果阈值testing通过一个nxn图像,只是下降到下一个级别,并比较它像一个2nx2n图像。 一旦你足够低,只是比较个别像素。 根据您的图像语料库,这可能会让您跳过大量的比较。

我会亲自去一个图像哈希algorithm。

图像哈希的目标是将图像内容转换成特征序列,以获得压缩表示。 这个特征序列(即一个比特向量)必须足够短,以便进行快速匹配,并保留用于相似性测量的可区分特征是可行的。

有几种algorithm可以通过开源社区免费获得。

在本文中可以find一个简单的例子,Neal Krawetz博士展示了平均散列algorithm的工作原理:

  1. 减小尺寸 。 删除高频和细节的最快方法是缩小图像。 在这种情况下,缩小到8×8,总共有64个像素。 不要担心保持宽高比,只需将其压扁至8×8平方。 这样,哈希将匹配任何图像的变化,无论规模或纵横比。
  2. 减less颜色 。 微小的8×8图片被转换成灰度。 这将64个像素(64个红色,64个绿色和64个蓝色)的哈希值更改为64个总的颜色。
  3. 平均颜色 。 计算64种颜色的平均值。
  4. 计算这些位 。 这是有趣的部分。 每一位都是根据颜色值是高于还是低于平均值来设置的。
  5. 构build哈希 。 将64位设置为64位整数。 顺序无关紧要,只要你一致。 (我使用big-endian从左到右,从上到下设置位。)

David Oftedal编写了一个C#命令行应用程序 ,可以使用Average Hashalgorithm对图像进行分类和比较。 (我用你的示例图片testing了他的实现,我有98.4%的相似度)。

这个解决scheme的主要好处是只读取一次图像,创build哈希值并根据它们的相似性对它们进行分类(例如,使用汉明距离 )。

这样就可以将特征提取阶段从分类阶段中分离出来,如果发现不够准确,可以轻松切换到另一个哈希algorithm。


编辑

你可以在这里find一个简单的例子(它包括一个40个图像的testing集,得到40/40分)。

商业的TinEye API是一个非常好的select。

过去我已经完成了图像匹配程序,现在的image processing技术是惊人的,它的先进性如此之高。

PS这里是你从谷歌拉从你的两个随机图片来自: http : //www.tineye.com/search/1ec9ebbf1b5b3b81cb52a7e8dbf42cb63126b4ea/

这里有一个话题讨论图像相似性的algorithm,已经在OpenCV库中实现。 在C#应用程序中导入低级函数应该没有问题。

由于这是一次性的工作,所以我会select一个脚本(select你喜欢的语言,我可能会selectPerl)和ImageMagick 。 尽pipe使用更多的代码,但您可以使用C#来完成与脚本相同的操作。 只需调用命令行实用程序并分析结果输出即可。

检查一对相似性的脚本大概是10行,如下所示:

首先检索尺寸与identify和检查纵横比几乎相同。 如果不是,则不匹配。 如果是这样,那么将较大的图像缩放到较小的尺寸,并进行convert 。 您应该事先尝试一下filter选项,以find在已知等价图像中产生最相似的图像。 其中九个可用。

然后使用compare函数产生一个相似性度量。 比较聪明的处理翻译和裁剪。 尝试find不会提供太多误报的相似性阈值。

我会做这样的事情:

  • 如果您已经知道模糊图像是如何模糊的,请在比较之前将相同的function应用于高质量的图像。

    • 然后用上面build议的最小二乘法比较图像。
    • 最低的价值应该给你一个匹配。 理想情况下,如果两张图像完全相同,您将得到0
    • 为了加快速度,您可以在下采样图像上执行大部分比较,然后优化图像的选定子采样
  • 如果您不知道,请尝试各种可能的function(JPEG压缩,缩减采样…)并重复

你可以尝试基于内容的图像检索 ( CBIR )。

说穿:

  1. 对于数据库中的每个图像,使用傅立叶变换生成指纹
  2. 加载源图像,制作图像的指纹
  3. 计算源和数据库中所有图像之间的欧几里得距离
  4. 对结果进行sorting

我认为这是一个混合的方法将是最好的解决您的特定批次匹配问题

  1. 将@Paolo Morretibuild议的图像散列algorithm应用于所有图像
  2. 对于一个集合中的每个图像,find一个哈希距离设置距离更近的图像子集
  3. 对于这个缩小的search空间,您现在可以应用@Running Wild或@Raskolnikovbuild议的昂贵的匹配方法…最好的赢了。

恕我直言,最好的解决办法是模糊两个图像,然后使用一些相似性度量(相关性/互信息等)来获得顶部K(K = 5可能?)的select。

如果从图像中提取轮廓,则可以使用ShapeContext获得图像的非常好的匹配。

ShapeContext是build立在这个确切的东西(比较基于相互形状的图像)

ShapeContext实现链接: 原始发布 关于ShapeContext 的主题 CodeProject页面 上的goot ppt

*您可能需要尝试一些“轮廓提取”技术,如阈值或傅立叶变换,或者看看这个CodeProject页面关于轮廓提取

祝你好运。

如果仅计算图像的像素差异,则只有在尺寸相同的图像或者您确切知道如何在水平和垂直方向上缩放图像的情况下才能使用,也不会有任何移位或旋转不变性。

所以我build议只有在问题最简单的情况下才使用像素差分度量(所有特性的图像都是相同的,但是质量不同,顺便说一句,为什么质量不同?jpeg工件或者重新缩放?),否则我build议使用归一化的互相关,它是更稳定的度量。 你可以用FFTW或OpenCV来完成。

如果质量差只是降低分辨率的结果,那么:

  • 将高质量图像重新调整为低质量图像分辨率(或重新调整为等于低分辨率)
  • 比较每个像素颜色以find最接近的匹配

因此,例如,将所有图像重新缩放到32×32并比较由像素设置的图像应该给你相当合理的结果,而且它仍然很容易做到。 虽然缩放方法可以在这里有所作为。

你可以尝试块匹配algorithm,虽然我不确定它确切的效果对你的具体问题 – http://scien.stanford.edu/pages/labsite/2001/ee368/projects2001/dropbox/project17/block.htmlhttp://www.aforgenet.com/framework/docs/html/05d0ab7d-a1ae-7ea5-9f7b-a966c7824669.htm

即使这不起作用,你仍然应该检查Aforge.net库。 有几个工具(包括从上面的块匹配),可以帮助你在这个过程中 – http://www.aforgenet.com/

我非常喜欢Running Wild的algorithm,如果能够使两幅图像更加相似,例如通过降低更好的图像的质量,我认为它会更有效。

Running Wild的答案非常接近。 你在这里做的是计算每个图像的峰值信噪比,或PSNR。 在你的情况下,你真的只需要均方误差,但它的平方分量帮助大量计算图像之间的差异。

PSNR参考

你的代码应该是这样的:

 sum = 0.0 for(imageHeight){ for(imageWidth){ errorR = firstImage(r,x,y) - secondImage(r,x,y) errorG = firstImage(g,x,y) - secondImage(g,x,y) errorB = firstImage(b,x,y) - secondImage(b,x,y) totalError = square(errorR) + square(errorG) + square(errorB) } sum += totalError } meanSquaredError = (sum / (imageHeight * imageWidth)) / 3 

我假设从两个数据库的图像显示相同的对话框,图像应接近相同,但质量不同? 然后匹配的图像将具有相同(或非常接近相同)的高宽比。

如果低质量图像是由高质量图像(或等效图像)产生的,则应该对高质量图像使用与预处理步骤相同的image processing过程,并与低质量图像数据库相匹配。 然后逐个像素比较或直方图匹配应该很好。

如果您有许多图像,图像匹配可以使用大量资源。 也许多通道的方法是一个好主意? 例如:第1遍:使用简单的方法比如纵横比来分组图像(db和width中的高度字段)(计算便宜)第2遍:匹配或分组第一色彩通道(或所有通道)低廉)

我也会推荐OpenCV。 你可以用c,c ++和Python(很快就可以用Java)来使用它。

大声思考:

如果您使用两个应该作为图层进行比较的图像并合并这些图像(从另一个中减去一个图像),您会得到一个新的图像(某些绘图程序可以编写脚本来进行批量转换,或者可以通过编写微小的DirectX或OpenGL程序)

接下来,你将不得不得到最终图像的亮度; 比赛越黑,比赛就越好。

你有没有尝试轮廓/阈值技术结合步行平均窗口(RGB值)?