在C#中比较两个图像的算法

Byy*_*yyo 52 c# hash image

我正在用C#编写一个工具来查找重复的图像.目前我创建了文件的MD5校验和并进行比较.

不幸的是我的图像可以

  • 旋转90度
  • 具有不同的尺寸(具有相同内容的较小图像)
  • 有不同的压缩或文件类型(例如jpeg工件,见下文)

在此输入图像描述在此输入图像描述

什么是解决这个问题的最佳方法?

fub*_*ubo 80

这是一个256位图像哈希的简单方法(MD5有128位)

  1. 将图片大小调整为16x16像素

16x16调整大小

  1. 将颜色减少为/(在此控制台输出中等于true/false)

在此输入图像描述

  1. 读取布尔值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;
}
Run Code Online (Sandbox Code Playgroud)

我知道,GetPixel不是那么快,但在16x16像素的图像上它不应该是瓶颈.

  1. 将此哈希值与其他图像的哈希值进行比较并添加容差.(可以与其他哈希值不同的像素数)

码:

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);
Run Code Online (Sandbox Code Playgroud)

所以这段代码能够找到相同的图像:

  • 不同的文件格式(例如jpg,png,bmp)
  • 旋转(90,180,270),水平/垂直翻转-通过改变迭代顺序ij
  • 不同的尺寸(需要相同的方面)
  • 不同的压缩(在像jpeg工件一样的质量损失的情况下需要公差) - 你可以接受99%的相同性为相同的图像,50%是不同的.
  • 彩色变为geyscaled,反之亦然(因为亮度与颜色无关)

更新/改进:

使用这种方法一段时间后,我注意到可以做的一些改进

  • 取代 GetPixel更多的表现
  • 使用exeif-thumbnail而不是读取整个图像以提高性能
  • 而不是设置0.5f在明暗之间的差异 - 使用所有256像素的明显中值亮度.否则,假设暗/亮图像是相同的,并且它能够检测具有改变的亮度的图像.
  • 如果你需要快速计算,使用bool[]或者List<bool>你需要存储很多哈希需要节省内存,使用a Bitarray因为布尔值没有存储在一个位,它需要一个字节!


Fab*_*Fab 7

你可以检查算法来比较两个图像,以便查看可用的图像比较方法.

除非您想自己重新创建完整的算法,否则您应该尝试使用现有的库或至少部分代码(只要他们的许可证适合您).

对于边缘检测和相关计算机视觉算法的开源C#实现,您可以尝试EmguCV,它是OpenCV的包装器.