1. ホーム
  2. c#

2枚の画像を比較するアルゴリズム(C#)

2023-09-04 10:06:11

質問

私はC#で重複した画像を見つけるためのツールを書いています。現在、私はファイルのMD5チェックサムを作成し、それらを比較します。

残念なことに、画像は

  • 90 度回転させたもの。
  • 異なる寸法を持つ(同じ内容でより小さな画像)。
  • 圧縮またはファイル タイプが異なる (例: JPEG アーティファクト。下記を参照)。

この問題を解決するためには、どのようなアプローチが良いでしょうか?

どのように解決するのですか?

256ビット(MD5は128ビット)の画像ハッシュを使った簡単な方法を紹介します。

  1. 画像のサイズを 16x16 ピクセル

  1. に色を減らす。 / (これは / 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;
}

知っている 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);

ということで、このコードは等しい画像を見つけることができます。

  • 異なるファイル形式 (例: jpg, png, bmp)
  • 回転 (90, 180, 270), 水平・垂直反転 - これは ij
  • 異なる寸法(同じアスペクトであることが必要)
  • 異なる圧縮 (jpeg アーチファクトのような品質低下の場合、許容範囲が必要) - 99% の等質性を同じ画像とし、50% を異なる画像として受け入れることができます。
  • 色がガイスケーリングに変更され、その逆も可能 (明るさは色に依存しないため)

更新・改善。

この方法をしばらく使ってみて、いくつかの改善点に気づきました。

  • を置き換える GetPixel より高いパフォーマンスのために
  • を使用して exeif-thumbnail を使用することで、画像全体を読み込む代わりにパフォーマンスを向上させることができます。
  • を設定する代わりに 0.5f を設定して明暗を区別するのではなく、256ピクセルすべての明度の中央値を使用します。そうしないと、暗い画像と明るい画像が同じであると見なされ、明るさが変化した画像を検出することができます。
  • が必要な場合は はやい の計算が必要な場合は bool[] または List<bool> メモリを節約する必要があり、多くのハッシュを保存する必要がある場合は Bitarray というのも、ブール値はビット単位で保存されるのではなく バイト !