【问题标题】:Finding matches between high quality and low quality, pixelated images - is it possible ? How?在高质量和低质量的像素化图像之间寻找匹配 - 有可能吗?如何?
【发布时间】:2012-07-25 03:25:27
【问题描述】:

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

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

我的任务是手动检查所有不良图像并将它们与良好图像进行匹配。

是否可以在一定程度上自动化这个过程?这是两个对话框的示例(从 Google 图片中随机提取):

所以我目前正在尝试用 C# 编写一个程序来从数据库中提取这些照片,循环浏览它们,找到具有共同形状的照片,并返回它们的 ID。我最好的选择是什么?

【问题讨论】:

  • Auwtch.. 祝你好运。我曾经尝试编写类似这样的程序作为挑战。挑战失败 :D 这些是一些非常难的算法。
  • 文件格式可以是jpg、png、gif……随便你;我可以在比较之前以编程方式进行转换。它们本机是 png :)
  • 如果图像 A 是图像 B 的模糊版本,这是否意味着图像 A 和 B 具有相同的尺寸?
  • 理想情况下,我想做到这一点,这样就不必一定是这样,@RunningWild,但我知道这会更加困难:)
  • @kgadek 他们应该只在质量上有所不同。如果还存在非特定于语言的算法,那将是非常令人印象深刻的:)

标签: c# image algorithm image-processing pattern-matching


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    Here's a topic 用算法讨论图像相似度,已经在OpenCV 库中实现。在 C# 应用程序中导入低级函数应该没有问题。

    【讨论】:

    • 你说得对,OpenCV 是这里的最佳选择,但在 C# 中使用它并非易事。如果发帖人可以选择使用 C++,我最喜欢你的回答。
    • @EkoostikMartin 您可以使用 EmguCV,它是 OpenCV 的 C~ 包装器
    • 我不会反对使用 C++...虽然我必须学习它;听起来很有趣 :-)。感谢您的回复!
    • 在最坏的情况下,poster 可以创建一个简单的外观 dll,用纯 C 编写,从而稍微简化对 OpenCV 的调用。但是,是的,@Aliostad 提到了 EmguCV,它可能是一个更好的解决方案。
    【解决方案3】:

    您可以尝试块匹配算法,尽管我不确定它对您的特定问题的确切有效性 - http://scien.stanford.edu/pages/labsite/2001/ee368/projects2001/dropbox/project17/block.html - http://www.aforgenet.com/framework/docs/html/05d0ab7d-a1ae-7ea5-9f7b-a966c7824669.htm

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

    【讨论】:

      【解决方案4】:

      我真的认为没有理由为此使用任何外部库,我已经多次做过此类事情,并且以下算法运行良好。我假设如果您要比较两张尺寸相同的图片,但如果它们不同,您可以调整其中一张的大小。

      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 += (r-R)*(r-R) + (g-G)*(g-G) + (b-B)*(b-B)
      badness /= (image width) * (image height)
      

      现在您已经获得了两个图像之间的标准化不良值,不良值越低,图像匹配的可能性就越大。这是简单而有效的,在某些情况下有很多东西可以让它更好或更快地工作,但你可能不需要这样的东西。您甚至不需要将坏度标准化,但是如果您想手动查看几个可能的匹配项,您只需为其设置一个阈值即可。


      由于这个问题引起了更多关注,因此我决定添加一种方法来加快处理多次图像的速度。当我需要比较数以万计的图像时,我使用了这种方法,并且我确信一对典型的图像会大不相同。我也知道我所有的图像都是完全相同的尺寸。在您比较对话框的情况下,您的典型图像可能大多是灰色的,并且您的某些图像可能需要调整大小(尽管这可能只是表示不匹配),在这种情况下,这种方法可能不会让您受益很多。

      这个想法是形成一个quad-tree,其中每个节点代表该节点代表的区域的平均 RGB 值。因此,4x4 图像的根节点的 RGB 值等于图像的平均 RGB 值,其子节点的 RGB 值代表其各自 2x2 区域的平均 RGB 值,它们的子节点将代表单个像素。 (实际上,最好不要超过大约 16x16 的区域,此时您应该开始比较单个像素。)

      在开始比较图像之前,您还需要确定不良阈值。您不会以任何可靠的准确度计算高于此阈值的错误,因此这基本上是您愿意将图像标记为“不匹配”的阈值。

      现在,当您比较图像 A 和图像 B 时,首先比较它们的四叉树表示的根节点。就像计算单个像素图像一样计算 badness,如果 badness 超过您的阈值,则立即返回并报告此级别的 badness。因为您使用的是标准化的坏度,并且由于坏度是使用平方差计算的,所以任何特定级别的坏度都将等于或小于较低级别的坏度,所以如果它在任何点超过阈值,你知道它也会超过单个像素级别的阈值。

      如果阈值测试在 nxn 图像上通过,只需下降到下一个级别并像它是 2nx2n 图像一样进行比较。一旦你变得足够低,只需比较各个像素。根据您的图像语料库,这可能会让您跳过很多比较。

      【讨论】:

      • 为了简单起见,就像这样,它基本上是“一个像素与 b 的匹配像素有多接近”,除非您可能需要缩放图像以使其与尺寸匹配
      • 这将非常低效。如果有 10,000 张图像,那么就是对整个图像进行 1 亿次比较。
      • @MikeKulls 你读过我发布的编辑吗?关键是您不会比较整个图像。
      • @RunningWild 是的,很抱歉我错过了。
      • 否则他会用手来做,所以我怀疑有那么多图片哈哈
      【解决方案5】:

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

      ShapeContext 就是为此而构建的(根据相互形状比较图像)

      ShapeContext 实现链接: Original publication A goot ppt on the subject CodeProject page about ShapeContext

      *您可能需要尝试一些“轮廓提取”技术,例如阈值或傅立叶变换,或查看CodeProject page about contour extraction

      祝你好运。

      【讨论】:

        【解决方案6】:

        我真的很喜欢 Running Wild 的算法,我认为如果你可以让两张图片更相似,它会更有效,例如降低更好的一张的质量。

        【讨论】:

          【解决方案7】:

          由于这是一次性工作,我会使用脚本(选择您最喜欢的语言;我可能会选择 Perl)和ImageMagick。您可以使用 C# 来完成与脚本相同的操作,但需要更多代码。只需调用命令行实用程序并解析结果输出。

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

          首先使用identify 检索尺寸并检查几乎相同的纵横比。如果不是,则不匹配。如果是这样,则使用convert 将较大的图像缩放到较小的大小。您应该提前使用filter 选项进行一些试验,以找到在已知等效图像中产生最相似性的选项。其中九个可用。

          然后使用compare 函数生成相似度度量。比较足够聪明,可以处理翻译和裁剪。尝试找到一个不会提供太多误报的相似度阈值。

          【讨论】:

            【解决方案8】:

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

            PSNR Reference

            您的代码应如下所示:

            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
            

            【讨论】:

              【解决方案9】:

              Commercial TinEye API 是一个非常好的选择。

              我过去做过图像匹配程序,现在的图像处理技术非常棒,非常先进。

              ps 这是你从谷歌中随机抽取的两张照片的来源:http://www.tineye.com/search/1ec9ebbf1b5b3b81cb52a7e8dbf42cb63126b4ea/

              【讨论】:

                【解决方案10】:

                如果您只计算图像的像素差异,则只有在相同大小的图像或您确切知道如何在水平和垂直方向上缩放它时才会起作用,而且您不会有任何移位或旋转不变性。

                因此,我建议仅在您遇到最简单形式的问题时才使用像素差异度量(图像在所有特征上都相同,但质量不同,顺便问一下,为什么质量不同?jpeg 伪影还是只是重新缩放?),否则我建议使用归一化互相关,它是更稳定的度量。 您可以使用 FFTW 或 OpenCV 来完成。

                【讨论】:

                  【解决方案11】:

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

                  如果低质量图像是从高质量图像(或等效图像)产生的,那么您应该使用与高质量图像预处理步骤相同的图像处理过程,并与低质量图像数据库匹配。然后逐像素比较或直方图匹配应该可以正常工作。

                  如果您有很多图像,图像匹配会占用大量资源。也许多通道方法是个好主意?例如: 第 1 阶段:使用简单的测量方法,如纵横比来对图像进行分组(db 中的宽度和高度字段?)(计算成本低) Pass 2:按直方图匹配或分组第一个颜色通道(或所有通道)(相对计算成本较低)

                  我也会推荐 OpenCV。您可以将它与 c、c++ 和 Python(以及很快的 Java)一起使用。

                  【讨论】:

                    【解决方案12】:

                    我会做这样的事情:

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

                      • 然后按照上面的建议使用最小二乘法比较图像。
                      • 最低值应该可以匹配。理想情况下,如果两张图片相同,您将得到 0
                      • 为了加快速度,您可以对降采样图像执行大部分比较,然后对图像的选定子样本进行细化
                    • 如果您不知道,请尝试各种可能的功能(JPEG 压缩、下采样等)并重复

                    【讨论】:

                      【解决方案13】:

                      我个人会选择图像哈希算法。

                      图像散列的目标是将图像内容转换为特征序列,以获得浓缩的表示。 此特征序列(即位向量)必须足够短,以便快速匹配并保留可区分的特征,以便进行相似度测量。

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

                      可以在this article 中找到一个简单的示例,Neal Krawetz 博士在其中展示了平均哈希算法的工作原理:

                      1. 缩小尺寸。去除高频和细节的最快方法是缩小图像。在这种情况下,将其缩小为 8x8,以便总共有 64 个像素。不要费心保持纵横比,只需将其压碎以适合 8x8 正方形。这样一来,哈希值将匹配图像的任何变化,无论比例或纵横比如何。
                      2. 减少颜色。微小的 8x8 图片被转换为灰度。这会将哈希值从 64 个像素(64 个红色、64 个绿色和 64 个蓝色)更改为 64 个总颜色。
                      3. 平均颜色。计算 64 种颜色的平均值。
                      4. 计算位。这是有趣的部分。每个位都是根据颜色值是高于还是低于平均值来设置的。
                      5. 构造哈希。将 64 位设置为 64 位整数。顺序无关紧要,只要您保持一致即可。 (我使用 big-endian 从左到右、从上到下设置位。)

                      David Oftedal 写了一个C# command-line application,它可以使用平均哈希算法对图像进行分类和比较。 (我用你的示例图像测试了他的实现,我得到了 98.4% 的相似度)。

                      此解决方案的主要好处是您只需读取每张图像一次,创建散列并根据它们的相似性对它们进行分类(例如,使用Hamming distance)。

                      通过这种方式,您可以将特征提取阶段与分类阶段解耦,如果您发现它不够准确,您可以轻松切换到另一种哈希算法。


                      编辑

                      您可以找到一个简单的示例here(它包括一个包含 40 张图像的测试集,并获得 40/40 的分数)。

                      【讨论】:

                      • @Simon Kiely 你试过这个吗?当前最流行的解决方案将非常耗费资源,因为它需要将每个图像的每个像素与其他每个图像进行比较。对于 10,000 张图像,即对整个图像进行 1 亿次比较。因为这里的解决方案非常有效,并且只需要读取每个图像一次。
                      • 这是一个非常有趣的答案。这绝对是我会研究的……98.4% 令人印象深刻。
                      • @Simon 你可以创建一个测试集,比如 100 张图像,看看它如何处理你的数据。
                      • @Simon:发布的样本图像之间的 98.4% 相似度(两个?)并不意味着,在大型语料库中,它实际上会工作得那么好。误报率也很重要。
                      • @tucuxi 我附上了一个带有 40 张图像的测试集的示例项目
                      【解决方案14】:

                      只是大声思考:

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

                      接下来,您必须获取生成图像的亮度;颜色越深,匹配越好。

                      【讨论】:

                        【解决方案15】:

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

                        • 将高质量图像重新缩放为低质量图像分辨率(或将两者重新缩放为相同的低分辨率)
                        • 比较每个像素颜色以找到最接近的匹配项

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

                        【讨论】:

                        • 只是一个友好的仅供参考:这与@NicolasBarbey 的答案基本相同。
                        【解决方案16】:

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

                        说白了:

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

                        【讨论】:

                          【解决方案17】:

                          我认为混合方法最能解决您的特定批次匹配问题

                          1. 将@Paolo Morreti 建议的Image Hashing algorithm 应用于所有图片
                          2. 对于一组中的每个图像,找到哈希值比设定距离更近的图像子集
                          3. 对于这个缩小的搜索空间,您现在可以应用 @Running Wild 或 @Raskolnikov 建议的昂贵的匹配方法......最好的一个获胜。

                          【讨论】:

                            【解决方案18】:

                            您是否尝试过将轮廓/阈值技术与移动平均窗口(RGB 值)结合使用?

                            【讨论】:

                              猜你喜欢
                              • 2018-08-09
                              • 1970-01-01
                              • 2018-02-16
                              • 1970-01-01
                              • 1970-01-01
                              • 2021-06-16
                              • 1970-01-01
                              • 2011-10-11
                              • 1970-01-01
                              相关资源
                              最近更新 更多