如何检查图像是否是另一个图像的缩放版本

时间:2010-08-06 08:54:36

标签: c# .net image

我正在寻找一种简便的方法来检查图像是否是另一个图像的缩放版本。它不一定非常快,它应该“相当”准确。并用.NET编写。而且是免费的。

我知道,一厢情愿: - )

我很确定,即使没有尝试过,将较大的图像转换为较小的图像并比较校验和也不起作用(特别是如果较小的版本是用另一个软件然后用.NET完成的话)。

下一个方法是缩小和比较像素。但首先,使用bool比较结果在所有像素上运行循环似乎是一个非常糟糕的主意,我相信会有一些像素关闭...

任何图书馆都会浮现在脑海中?回到大学我们有一些MPEG7课程,所以我正在考虑使用音调分布,亮度等“统计”的组合。

该主题的任何想法或链接?

谢谢, 克里斯

7 个答案:

答案 0 :(得分:3)

我认为这将是您最好的解决方案。首先检查宽高比。然后将图像缩放到2中的较小者,如果它们的大小不同的话。最后,对2个图像进行哈希比较。这比进行像素比较快得多。我在其他人的帖子中找到了哈希比较方法,并在此处调整了答案以适应。我试图想出一个最好的方法来做一个项目,我将不得不比较超过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 :(得分:1)

实现这一目标的一个想法是:

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

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

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

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

构建匹配和失败的计数,并使用边界来确定它是否被视为匹配。

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

答案 2 :(得分:1)

只需将较大的图像缩放回较小的图像,然后通过获取每个红色,绿色和蓝色分量的差值的绝对值来比较每个像素。

然后,您可以设置一个阈值,用于决定将其计为匹配所需的距离,例如如果95%以上的像素在颜色值的5%范围内,则匹配。

模糊匹配是必要的,因为您可能具有缩放伪像/抗锯齿效果。

答案 3 :(得分:0)

你必须在某个时刻循环像素。 容易实现但非常强大的东西是计算每个像素的各个颜色分量(RGB)之间的差异,找到平均值,并查看它是否超过某个阈值。它当然不是最好的方法,但要快速检查它应该做。

答案 4 :(得分:0)

最简单的方法是将最大的图像缩放到较小的图像尺寸并比较色差。由于您不知道缩放是立方体还是线性(或其他),您必须接受一个小的差异。

不要忘记取每个像素差异的绝对值。 ;)

答案 5 :(得分:0)

我已经大致说过Tom Gullen,除非我在比较之前将较大的图像缩小到较小的图像(否则如果您将25x25与30x30或其他东西进行比较,那么您将获得更难的数学)

根据图像尺寸,我可能会考虑的另一件事是将它们两个缩小到较小的图像。也就是说,如果你有一个4000x4000而另一个是3000x3000,那么你可以将它们缩小到200x200并将它们与那个尺寸进行比较。

正如其他人所说,然后你需要检查一个阈值(最好是颜色组件)并确定哪种公差效果最好。我建议这可能最好通过反复试验来完成。

答案 6 :(得分:0)

在这方面绝对没有权威或经验,我会帮助你。

我开始使用宽高比匹配一些容差,除非你比较裁剪的图像部分,这会让事情变得更难。

然后我会扫描像素中的相似区域,不准确,再次需要公差等级。然后当一个区域相似时,沿着一条直线相互比较,并找到另一个类似颜色的区域。黑与...白色会变得更难。

如果你受到了打击,你会在一行中有两个相似的补丁区域。有两个点,你可以在它们之间有一个长度参考,所以现在你可以看到缩放可能是什么。您也可以先缩放图像,但这并不能解决方面不匹配的裁剪部分。

现在在源图像中选择一个随机点并获取颜色信息。然后使用比例因子,在另一个图像上找到相同的随机点,并查看颜色是否检出。用随机点做几次。如果很多人出现类似情况,那很可能就是副本。

然后,您可能希望将其标记为进一步的CPU密集型检查。逐像素比较或其他。

我知道微软(Photosynth)使用类似“大纲”(Photoshop中的那种东西)的过滤器来移除图像颜色,只留下宽大的线条,只留下图片的“组件”进行匹配(它们匹配边界和重叠)。

为了速度,我会把问题分解成块,并且真的想想人类如何决定两张照片是否相似。对于非速度,详尽地比较颜色可能会让你到那里。

简短的过程:

如果你打孔一张纸随机打了4次,然后把它放在两张照片上,只要看到你看到的颜色就可以判断它们是否可能是副本而需要进一步检查。