Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/271.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# C语言中两幅图像的比较算法#_C#_Image_Hash - Fatal编程技术网

C# C语言中两幅图像的比较算法#

C# C语言中两幅图像的比较算法#,c#,image,hash,C#,Image,Hash,我正在用C#编写一个工具来查找重复的图像。目前,我创建了文件的MD5校验和,并比较了它们 不幸的是,图像可能是: 旋转90度 具有不同的尺寸(具有相同内容的较小图像) 具有不同的压缩或文件类型(例如jpeg瑕疵,见下文) 解决此问题的最佳方法是什么?下面是一个使用256位图像哈希的简单方法(MD5有128位) 将图片大小调整为16x16像素 将颜色减少为黑色/白色(此控制台输出中等于真/假) 将布尔值读入列表——这是散列 代码: public static List<bool&g

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

不幸的是,图像可能是:

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


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

下面是一个使用256位图像哈希的简单方法(MD5有128位)

  • 将图片大小调整为16x16像素
  • 将颜色减少为黑色/白色(此控制台输出中等于/
  • 将布尔值读入
    列表
    ——这是散列
  • 代码

    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;
    }
    
    因此,此代码能够找到具有以下功能的相同图像:

    • 不同的文件格式(例如jpg、png、bmp)
    • 旋转(90、180、270),水平/垂直翻转-通过改变
      i
      j
    • 不同的尺寸(需要相同的外观)
    • 不同的压缩(在质量损失(如jpeg伪影)的情况下需要公差)-您可以接受99%的相等性表示相同的图像,50%表示不同的图像
    • 颜色更改为geyscaled,反之亦然(因为亮度与颜色无关)
    更新/改进:

    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);
    
    使用此方法一段时间后,我注意到可以做一些改进

    • GetPixel
      获得更高的性能
    • 使用而不是读取整个图像以提高性能
    • 不要将
      0.5f
      设置为明暗不同,而是使用所有256像素的不同中值亮度。否则,暗/光图像被假定为相同的,并且它能够检测具有改变的亮度的图像
    • 如果您需要计算,请使用
      bool[]
      List
      如果您需要存储大量哈希值并需要节省内存,请使用
      Bitarray
      因为布尔值不是存储在一个位中,它需要一段时间
    将图像重新采样到某个常见分辨率后,您可以使用小波分解并比较此分解的系数,而不是图像本身。仅比较前N个系数将使该方法对噪声和其他伪影更具鲁棒性

    小波有几种C#实现。例如,您可以通过检查查看可用的图像比较方法

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


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

    有趣的问题,鉴于此,图像的比较并不难

  • 这些图像是相同的(第一个图像不是第二个图像的一部分,反之亦然)
  • 图像仅旋转90度的倍数
  • 进行比较的一种方法是

  • 将两个图像的大小调整为最小直径
  • 对每个图像应用边缘检测,生成黑白图像(或0和1的数组)
  • 比较生成的位图(保持第一个位图静止,将第二个位图旋转90度3次),计算匹配像素的百分比并获得最大高度值
  • 现在如果这个值在一个合理的范围内,比如说90%(可能需要通过做一些实验来确定),那么你可以安全地假设两者都是相同的,但是如果

  • 例如,即使角上有几个像素不同,第二个图像也会从第一个图像裁剪而来
  • 图像旋转的角度不是90度的倍数(尽管这不太可能)
  • private List colorList=new List();
    私有字符串散列;
    私有字符串GetImageHash(位图bmpSource)
    {
    colorList.Clear();
    int i,j;
    位图bmpMin=新位图(bmpSource,新大小(16,16));//创建具有16x16像素的新图像
    对于(j=0;j
    这里的高级内容不错,但很多图像实际上都是同一个文件。我要考虑的一个措施是先做哑巴部分。创建一个目录列表,并按大小顺序对图像文件进行排序。找到具有相同大小文件的所有对,并检查每对是否完全匹配。对于每个匹配项,您可以删除双精度

    现在来看有趣的部分


    在上述解决方案中,有一件事是没有想到的,那就是利用颜色。您可以使用颜色直方图进行比较。对于红色、绿色和蓝色通道,对每个颜色出现进行计数,并将计数放入树整数[255]数组中。然后将每个RGB数组规格化为浮点[0.0..1.0]值,并作为矢量3(RGB)距离进行比较。这种方法可以找到图像的旋转和调整大小的版本。颜色域中的匹配不能保证。。但是,您可以使用它(再次)对文件进行分组,以进一步优化处理并加快处理速度。

    使用边缘检测将两个图像缩放到相同大小,然后计算表示差异程度的值(与所有旋转相比)我的帮助-读到这里真的很有趣,但是,只有当图片使用完全相同的算法和完全相同的设置进行修改时,否则您可能会
    private List<byte> colorList = new List<byte>();
    private string hash;
    
    private string GetImageHash(Bitmap bmpSource)
    {
        colorList.Clear();
        int i,j;
        Bitmap bmpMin = new Bitmap(bmpSource, new Size(16, 16)); //create new image with 16x16 pixel
        for ( j = 0 ; j < bmpMin.Height; j++)
        {
            for ( i = 0; i < bmpMin.Width; i++)
            {
                colorList.Add(bmpMin.GetPixel(i, j).R);
            }
        }
        SHA1Managed sha = new SHA1Managed();
        byte[] checksum = sha.ComputeHash(colorList.ToArray());
        hash = BitConverter.ToString(checksum).Replace("-", String.Empty);
        sha.Dispose();
        bmpMin.Dispose();
        return hash;
    }