匹配具有不同文件名的两个相同图像

时间:2011-05-13 16:13:35

标签: c# image

如果单个图像已使用两个不同的文件名保存两次,有没有办法比较它们以查看它们是否相同..?

我希望基本的哈希或CRC类型检查可以工作..?

文件大小可能没有,因为池中有数百万个图像,不同的图像可能具有相同的大小..

希望在C#中有一种简单的方法。

5 个答案:

答案 0 :(得分:7)

如果文件内容相同,那么加密哈希至少会给出相同的非常好的指示。 SHA256课程在这里是一个很好的候选人,虽然它可能有点超过顶部。例如:

static byte[] Sha256HashFile(string file)
{
    using (SHA256 sha256 = SHA256.Create())
    {
        using (Stream input = File.OpenRead(file))
        {
            return sha256.ComputeHash(input);
        }
    }
}

比较两个返回的字节数组的最简单方法可能是使用Convert.ToBase64将它们转换为字符串,然后比较字符串。丑陋但很容易:)你也可以使用Enumerable.SequenceEqual

byte[] hash1 = Sha256HashFile("file1.png");
byte[] hash2 = Sha256HashFile("file2.png");
bool same = hash1.SequenceEqual(hash2);    

如果要将哈希值存储为集合或字典,可以实现自己的IEqualityComparer<byte[]>,但坦率地说,最简单的方法是使用base64字符串。例如,这将打印出重复的文件:

var hashToNameMap = new Dictionary<string, string>();
foreach (string file in files)
{
    byte[] hash = Sha256HashFile(file);
    string base64 = Convert.ToBase64(hash);
    string existingName;
    if (hashToNameMap.TryGetValue(base64, out existingName))
    {
        Console.WriteLine("{0} is a duplicate of {1}", file, existingName);
    }
    else
    {
        hashToNameMap[base64] = file;
    }
}

一些注意事项:

  • 这不是保证准确,但发生碰撞的可能性非常小,特别是如果文件也必须是有效的图像。
  • 这涉及读取所有 文件的所有 - 即使没有其他文件具有相同的大小(因此也没有可能重复的文件)。这对您来说可能是也可能不是问题。
  • 即使多个相同大小的文件,您只需要阅读所有文件以查找重复文件...您可以随时读取文件并计算哈希值,停止只要你发现文件不同。

您如何处理这取决于您的目标是绝对速度,代码的简单性等。它还可能取决于池是否会随着时间的推移而增长 - 例如,您可能希望在获得两个文件时立即散列文件或者更多相同大小的文件,这样当你添加另一个相同大小的文件时,你可以哈希那个并添加它而不需要重新读取现有数据。

答案 1 :(得分:4)

首先,检查长度。只有当它们匹配时,你才能看得更深。

对于具有相同大小的所有图像,请计算哈希值。当哈希匹配时,您可以相当确定图像是否相同。该库提供了许多加密安全哈希,但您可能希望寻找优化:

  • 样品。如果您的图像很大(> 100 kB),您可以通过仅在几个段上计算哈希来节省I / O.在开始,中间和结束时几KB就足以获得良好的指纹。对这些块的大小和偏移使用512的倍数。 Jpeg压缩有点像Hash:一些像素差异通常会导致比特流的巨大差异。

  • 使用更快的哈希。在这种情况下,简单的xor算法就足够了。

  • 如果你真的想一次比较两个图像,那么使用哈希实现让你检查中间结果。只要有差异,你就可以停下来。

  • 但是当你有很多相同大小的文件时,每个文件计算一次Hash并找到(Size,Hash)重复文件。

答案 2 :(得分:1)

in

System.Security.Cryptography;

使用SHA1

using(SHA1 sha = SHA1.Create()) { //added using based on Jon Skeet comment
    byte[] newData = sha.ComputeHash(data);
}

data是文件的byte []数据

newData是哈希

这只适用于你想知道两个图像文件是否字面上相同的字节,而不是它们只是编码相同的像素(如果元数据不同可能是不同的文件)

答案 3 :(得分:0)

您可以从每个文件中读取二进制文件,然后比较包含的二进制文件。相同的图像应该在每个数组中具有完全相同的二进制。

只是一个想法。

答案 4 :(得分:0)

您也可以这样做

public string ImageToBase64(Image image, 
                            System.Drawing.Imaging.ImageFormat format)
{ 
    using (MemoryStream ms = new MemoryStream())
    { 
         // Convert Image to byte[]
         image.Save(ms, format);  
         byte[] imageBytes = ms.ToArray();

        // Convert byte[] to Base64 String
        string base64String = Convert.ToBase64String(imageBytes);
        return base64String; 
    }
}

然后你可以做一个String.Compare()。这对于较大的图片来说可能很慢,因为它会生成一个相当大的字符串,但我只是为了completnes而发布它:)