如何检查一张图片是否是另一张图片的缩放版本

5
给定两个图像,我如何轻松地检查一个图像是否是另一个图像的缩放版本?
性能不是问题;它只需要合理准确,并在.NET平台上工作。
我考虑过将较大的图像缩小以匹配较小的图像,然后通过比较图像校验和或在重新缩放后迭代比较单个像素来进行比较;但这些方法只能捕捉到完全匹配,而通过将原始较小图像放大然后缩小,似乎不太可能得到完全匹配。
也许可以通过使用"统计"的组合,如色调分布、亮度等方式来实现?
7个回答

5

我认为这将是您最佳的解决方案。首先检查纵横比,然后将图像缩放到较小的一侧,如果它们的尺寸不相同。最后,进行两幅图像的哈希比较。这比像素比较快得多。我在别人的帖子中发现了哈希比较方法,并将答案适应到这里。我正在为一个需要比较超过5200个图像的项目中想出最好的方法。在读了这里的一些帖子之后,我意识到我已经拥有了所有必要的内容,并决定分享。

public class CompareImages2
    {
        public enum CompareResult
        {
            ciCompareOk,
            ciPixelMismatch,
            ciAspectMismatch
        };

        public static CompareResult Compare(Bitmap bmp1, Bitmap bmp2)
        {
            CompareResult cr = CompareResult.ciCompareOk;

            //Test to see if we have the same size of image
            if (bmp1.Size.Height / bmp1.Size.Width == bmp2.Size.Height / bmp2.Size.Width)
            {
                if (bmp1.Size != bmp2.Size)
                {
                    if (bmp1.Size.Height > bmp2.Size.Height)
                    {
                        bmp1 = (new Bitmap(bmp1, bmp2.Size));
                    }
                    else if (bmp1.Size.Height < bmp2.Size.Height)
                    {
                        bmp2 = (new Bitmap(bmp2, bmp1.Size));
                    }
                }

                //Convert each image to a byte array
                System.Drawing.ImageConverter ic = new System.Drawing.ImageConverter();
                byte[] btImage1 = new byte[1];
                btImage1 = (byte[])ic.ConvertTo(bmp1, btImage1.GetType());
                byte[] btImage2 = new byte[1];
                btImage2 = (byte[])ic.ConvertTo(bmp2, btImage2.GetType());

                //Compute a hash for each image
                SHA256Managed shaM = new SHA256Managed();
                byte[] hash1 = shaM.ComputeHash(btImage1);
                byte[] hash2 = shaM.ComputeHash(btImage2);

                //Compare the hash values
                for (int i = 0; i < hash1.Length && i < hash2.Length && cr == CompareResult.ciCompareOk; i++)
                {
                    if (hash1[i] != hash2[i])
                        cr = CompareResult.ciPixelMismatch;

                }
            }
            else cr = CompareResult.ciAspectMismatch;
            return cr;
        }
    }

1

实现这个想法的一个方法:

如果图像是10x10,而您的原始图像是40x40

循环遍历10x10中的每个像素,然后检索代表该循环像素的4个像素。

因此,对于较小图像中的每个像素,请找到较大图像中相应的缩放像素数量。

然后,您可以取4个像素的平均颜色,并与较小图像中的像素进行比较。您可以指定误差范围,即-10%或+10%范围被视为匹配,其他则被视为失败。

建立匹配和失败的计数,并使用范围确定是否将其视为匹配。

我认为这可能比将图像缩放到相同大小并进行1像素:1像素比较要更好,因为我不确定调整大小算法如何必要工作,您可能会失去一些细节,从而得到不太准确的结果。或者可能有不同的调整图像大小的方法和方法。但是,再次强调,我不知道调整大小的方式取决于您如何进行操作。


如果缩小版本的颜色也稍微调整一下呢? - BerggreenDK

1

只需将较大的图像缩小到与较小的图像相同的大小,然后通过获取每个红色、绿色和蓝色分量之间差异的绝对值来比较每个像素。

然后,您可以设置一个阈值来决定需要多接近才能将其视为匹配,例如,如果95%以上的像素在颜色值的5%范围内,则表示匹配。

模糊匹配是必要的,因为您可能会遇到缩放伪影/抗锯齿效果。


0
你必须在某个时候循环遍历像素。 一个易于实现但相当强大的方法是计算每个像素的单个颜色分量(RGB)之间的差异,找到平均值,并查看是否超过了某个阈值。这肯定不是最好的方法,但对于快速检查应该足够了。

0

最简单的方法就是将最大的图像缩放到较小图像的大小并比较颜色差异。由于您不知道缩放是立方还是线性(或其他),因此必须接受轻微的差异。

别忘了取每个像素差的绝对值. ;)


0

我会说的和Tom Gullen差不多,只是在比较之前,我会将大图缩小到与小图相同的尺寸(否则,如果你比较一个25x25的图像和一个30x30的图像,你就需要进行复杂的数学计算)。

另外一件事情是,根据图像大小的不同,我可能会考虑将它们同时缩小到一个更小的图像。例如,如果你有一个4000x4000的图像和另一个3000x3000的图像,那么你可以将它们都缩小到200x200并在该尺寸下进行比较。

正如其他人所说,然后你需要使用阈值检查(最好是在颜色组件上),并决定哪些容差效果最好。我建议这最好通过试错来完成。


0

我在这个领域绝对没有任何权威或经验,但我会试着帮助你。

首先,我会通过一定的公差匹配宽高比,除非你正在比较图像的裁剪部分,否则会使事情变得更加困难。

然后,我会扫描相似区域的像素,不需要完全准确,再次需要一个公差级别。然后,在找到类似区域时,沿着一条直线比较两个区域并找到另一个颜色相似的区域。黑白颜色将更加困难。

如果你找到了匹配,你将获得两个具有相似度补丁的连续区域。有了两个点,你就可以得到它们之间的长度参考,因此现在你可以看到缩放可能是多少。你也可以先缩放图像,但这不能解决宽高比不匹配的裁剪部分问题。

现在在源图像中选择一个随机点,并获取颜色信息。然后使用比例因子,在其他图像上找到同样的随机点,并查看颜色是否匹配。用几个随机点试一试。如果有很多相似的结果,那么很可能是一份副本。

然后,你可能希望将其标记为进一步、更耗费计算机资源的检查。可以逐像素进行比较或其他操作。

我知道微软(Photosynth)使用像“轮廓”(在Photoshop中的那种东西)这样的过滤器来去除图像颜色,只留下螺旋线,这些螺旋线只留下图片的“组成部分”以进行匹配(它们匹配边界和重叠部分)。

为了提高速度,我会将问题分解成块,并仔细考虑人类如何判断两张照片是否相似。对于非速度要求的情况,详尽地比较颜色可能会让你达到目标。

简而言之,该过程如下:

如果您随机地在一张纸上打了4个洞,然后将其放在两张照片上方,仅通过看到透过来的颜色,您就可以判断它们是否可能是副本并需要进一步检查。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接