【问题标题】:What is the best way to compare images in a bitmap list比较位图列表中图像的最佳方法是什么
【发布时间】:2018-06-07 13:20:57
【问题描述】:

我正在开发一个应用程序,我可以在一个列表中加载多张图片,并将该列表中的每张图片相互比较,以便找到重复的图片。

所以首先我成功获取了图片并将它们加载到IList<Bitmap>

 public IList<Bitmap> getPictures()
        {
            IList<Bitmap> pictures = new List<Bitmap>();

            string filepath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
            DirectoryInfo d = new DirectoryInfo(filepath+ "\\Phone Pictures\\");
            foreach (var picture in d.GetFiles("*.png"))
            {
                pictures.Add(ConvertToBitmap(picture.FullName));
            }
                return pictures;
        }

比我使用预制的图像比较算法:

public static CompareResult Compare(Bitmap bmp1, Bitmap bmp2)
        {
            CompareResult cr = CompareResult.ciCompareOk;

            //Test to see if we have the same size of image
            if (bmp1.Size != bmp2.Size)
            {
                cr = CompareResult.ciSizeMismatch;
            }
            else
            {
                //Convert each image to a byte array
                System.Drawing.ImageConverter ic =
                       new System.Drawing.ImageConverter();
                byte[] btImage1 = new byte[1];
                btImage1 = (byte[])ic.ConvertTo(bmp1, btImage1.GetType());
                byte[] btImage2 = new byte[1];
                btImage2 = (byte[])ic.ConvertTo(bmp2, btImage2.GetType());

                //Compute a hash for each image
                SHA256Managed shaM = new SHA256Managed();
                byte[] hash1 = shaM.ComputeHash(btImage1);
                byte[] hash2 = shaM.ComputeHash(btImage2);

                //Compare the hash values
                for (int i = 0; i < hash1.Length && i < hash2.Length
                                  && cr == CompareResult.ciCompareOk; i++)
                {
                    if (hash1[i] != hash2[i])
                        cr = CompareResult.ciPixelMismatch;
                }
            }
            return cr;
        } 

现在这就是我尝试调用算法并将其应用于我加载的列表的方式:

public void ComparePictureList()
        {

            IList<Bitmap> picturesList = getPictures();

            foreach (var picture1 in picturesList)
            {
                foreach( var picture2 in picturesList)
                {
                    Compare(picture1, picture2);
                }
            }

        }

但是有没有更好的方法将我的算法应用到我的列表中,我的意思是,不是声明 2 个循环 picture1picture2.NET 框架中是否有任何功能可以更好?

P.S:对于任何想知道ConvertToBitmap 是什么的人,就是这样:

   public Bitmap ConvertToBitmap(string fileName)
        {
            Bitmap bitmap;
            using (Stream bmpStream = System.IO.File.Open(fileName, System.IO.FileMode.Open))
            {
                Image image = Image.FromStream(bmpStream);

                bitmap = new Bitmap(image);

            }
            return bitmap;
        }

【问题讨论】:

  • 而不是List&lt;Bitmap&gt;,我会将它保存为定义为{Image, Hash} 的自定义类,这样哈希就只需要计算一次。如果处理图像,该类也可以负责。根据应用的功能,路径名等其他信息也可能很方便。
  • 您不应该在列表中导航两次,因为list[a] = list[b] 应该等于list[b] = list[a]
  • @RubensFarias 是的,这是我试图避免做的第一件事

标签: c# algorithm performance


【解决方案1】:

我会避免为同一张图像多次计算哈希,并且只循环一次图像:

public static void Main(string[] args)
{
    var files = new Dictionary<string, string>();
    foreach (var file in Directory.GetFiles("c:\\", "*.png"))
    {
        files.Add(file, CalculateHash(file));
    }

    var duplicates = files.GroupBy(item => item.Value).Where(group => group.Count() > 1);
}

private static string CalculateHash(string file)
{
    using (var stream = File.OpenRead(file))
    {
        var sha = new SHA256Managed();
        var checksum = sha.ComputeHash(stream);
        return BitConverter.ToString(checksum).Replace("-", String.Empty);
    }
}

【讨论】:

  • 但这不起作用,因为具有相同元素的两个 byte[] 数组不被认为是相等的(对于 GroupBy 也是如此),因此此代码不会检测到重复项(同样,Directory.GetFiles 将失败这样的论点,但这不是很重要)。
  • 很好,@Evk,抱歉我的懒惰回答。我刚刚修好了。
【解决方案2】:

您已经在计算每个图像的哈希值,因此您可以将其转换为例如String 然后只使用 Dictionary&lt;String, Bitmap&gt; 其中 Key 将是哈希。可以使用ContainsKey快速判断图片哈希是否已经在列表中。

由于您是通过流打开图像文件,因此有一种更简单的方法可以从Stream 计算哈希值,如Calculate the Hash of the Contents of a File in C#? 所述。您可能需要倒带才能读取图像。

【讨论】:

  • 哦,这是我没想到的有趣方法,谢谢!
【解决方案3】:
  1. 您无法确定具有相同哈希值的两个图像是否相等。

  2. 如果您的哈希函数使用图像的所有字节,您可以更快地比较图像的字节,而不是计算哈希并进行比较。

  3. 您多次计算每个图像的哈希值。您不需要这样做。

我建议执行以下操作:

  1. 计算每张图片的哈希值并存储。

  2. 使用映射或两个循环来查找哈希冲突。

  3. 需要逐字节比较具有相同哈希值的图像,以确保它们相等。

【讨论】:

    猜你喜欢
    • 2020-08-07
    • 1970-01-01
    • 2021-12-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-03
    • 2013-05-23
    • 2015-08-21
    相关资源
    最近更新 更多