我正在用 C# 编写一个工具来查找重复的图像。目前,我创建文件的 MD5 校验和并进行比较。
不幸的是,图像可能是:
- 旋转 90 度。
- 具有不同的尺寸(较小的图像但内容相同)。
- 具有不同的压缩或文件类型(例如 jpeg 工件,见下文)。
解决这个问题的最佳方法是什么?
最佳答案
这是一个使用 256 位图像哈希的简单方法(MD5 有 128 位)
- 将图片调整为16x16像素
- 将颜色减少为黑色/白色(在此控制台输出中等于true/false)<
- 将 bool 值读入
List<bool>
- 这是散列
代码:
public static List<bool> GetHash(Bitmap bmpSource)
{
List<bool> lResult = new List<bool>();
//create new image with 16x16 pixel
Bitmap bmpMin = new Bitmap(bmpSource, new Size(16, 16));
for (int j = 0; j < bmpMin.Height; j++)
{
for (int i = 0; i < bmpMin.Width; i++)
{
//reduce colors to true / false
lResult.Add(bmpMin.GetPixel(i, j).GetBrightness() < 0.5f);
}
}
return lResult;
}
我知道,GetPixel
不是那么快,但在 16x16 像素的图像上它不应该是瓶颈。
- 将此散列值与其他图像的散列值进行比较并添加容差。(可以与其他散列值不同的像素数)
代码:
List<bool> iHash1 = GetHash(new Bitmap(@"C:\mykoala1.jpg"));
List<bool> iHash2 = GetHash(new Bitmap(@"C:\mykoala2.jpg"));
//determine the number of equal pixel (x of 256)
int equalElements = iHash1.Zip(iHash2, (i, j) => i == j).Count(eq => eq);
所以这段代码能够找到相同的图像:
- 不同的文件格式(例如 jpg、png、bmp)
- 旋转 (90, 180, 270),水平/垂直翻转 - 通过改变
i
的迭代顺序和j
- 不同的维度(需要相同的方面)
- 不同的压缩(在质量损失的情况下需要容忍,例如 jpeg 伪影)- 您可以接受 99% 的平等是同一图像,50% 的平等是不同的图像。
- colored 更改为 geyscaled,反之亦然(因为亮度与颜色无关)
更新/改进:
在使用这种方法一段时间后,我注意到可以做一些改进
- replacing
GetPixel
为了更好的表现 - 使用exeif-thumbnail而不是读取整个图像以提高性能
- 而不是设置
0.5f
区分明暗 - 使用所有 256 个像素的不同中值亮度。否则,暗/亮图像被假定为相同,并且它能够检测亮度发生变化的图像。 - 如果你需要fast计算,使用
bool[]
或List<bool>
如果您需要存储大量哈希值以节省内存,请使用Bitarray
因为 bool 值没有存储在位中,所以它需要一个 byte !
关于c# - 在 C# 中比较两个图像的算法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35151067/