匹配两个具有不同文件名的相同图像
本文关键字:文件名 图像 两个 | 更新日期: 2023-09-27 17:56:17
如果一张图像用两个不同的文件名保存了两次,有没有办法比较它们以查看它们是否相同..?
我希望基本的哈希或CRC类型检查可以工作..?
文件大小可能不会,因为池中有数百万张图像,不同的图像可能具有相同的大小。
希望在 C# 中有一种简单的方法可以做到这一点。
如果文件内容相同,那么加密哈希至少可以很好地指示相等性。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;
}
}
一些注意事项:
- 这不能保证是准确的,但发生冲突的可能性非常小,特别是如果文件也必须是有效的图像。
- 这涉及读取所有文件 - 即使没有其他具有相同大小的文件(因此没有可能的副本)。这对您来说可能是也可能不是问题。
- 即使有多个相同大小的文件,您也只需要阅读所有文件即可找到重复项......您可能会随时读取文件并计算哈希,一旦发现文件不同,就会停止。
你如何处理这取决于你的目标是绝对速度、代码的简单性等。它还可能取决于池是否会随着时间的推移而增长 - 例如,您可能希望在获得两个或更多相同大小的文件后立即对文件进行哈希处理,以便在添加另一个相同大小的文件时,您可以对其进行哈希处理并添加它,而无需重新读取现有数据。
首先,无论如何都要检查长度。只有当它们匹配时,您才必须更深入地观察。
对于具有相同大小的所有图像,请计算哈希。当哈希匹配时,您可以相当确定图像是相同的。该库提供了许多加密安全的哈希,但您可能需要寻找优化:
-
样本。如果图像很大(> 100 kB),则可以通过仅计算几个段的哈希来节省 I/O。开头、中间和结尾的几kB可能足以获得一个好的指纹。请使用 512 的倍数作为这些块的大小和偏移量。 Jpeg压缩的工作方式有点像哈希:几个像素的差异通常会导致比特流的巨大差异。
-
使用更快的哈希。在这种情况下,一个简单的异或算法可能就足够了。
-
如果您真的想一次比较 2 张图像,请使用 Hash 实现,让您检查中间结果。一旦有差异,你就可以停止。
- 但是,当您有很多相同大小的文件时,请为每个文件计算一次哈希并找到(大小,哈希)重复项。
in
System.Security.Cryptography;
使用 SHA1
using(SHA1 sha = SHA1.Create()) { //added using based on Jon Skeet comment
byte[] newData = sha.ComputeHash(data);
}
数据是文件的字节[]数据
newData 是哈希
这仅适用于您想知道两个图像文件是否实际上是相同的字节,而不是它们只是编码相同的像素(如果元数据不同,则可能是不同的文件)
您可以从每个文件中读取二进制文件,然后比较包含的二进制文件。同一图像在每个数组中应具有完全相同的二进制文件。
只是一个想法。
做这样的事情
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()
.对于较大的图片来说,这可能很慢,因为它会生成一个相当大的字符串,但我发布它只是为了完成:)