web-dev-qa-db-ja.com

C#で2つの画像を比較するアルゴリズム

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

残念ながら私の画像は

  • 90度回転
  • 寸法が異なる(同じコンテンツの小さい画像)
  • 異なる圧縮またはファイルタイプがあります(例:jpegアーティファクト、以下を参照)

enter image description hereenter image description here

この問題を解決するための最良のアプローチは何でしょうか?

49
Byyo

256ビットのイメージハッシュ(MD5は128ビット)を使用した簡単なアプローチを次に示します。

  1. 画像のサイズを16x16ピクセルに変更します

16x16 resized

  1. 色をblack/whitetrue/falseこのコンソール出力)

enter image description here

  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)、水平/垂直反転-iおよびjの反復順序を変更することにより
  • 異なる寸法(同じアスペクトが必要です)
  • 異なる圧縮(jpegアーティファクトのような品質低下の場合、許容値が必要です)-99%の同等性を受け入れ、同じイメージを50%受け入れ、異なるイメージを受け入れられます。
  • 色はgeyscaledに変更され、逆も同様です(明るさが色に依存しないため)

更新/改善:

この方法をしばらく使用した後、いくつかの改善点に気づいた

  • 置換GetPixelはパフォーマンスを向上させます
  • パフォーマンス向上のためにイメージ全体を読み取る代わりに exeif-thumbnail を使用する
  • 0.5fを明暗で異なる値に設定する代わりに、256ピクセルすべての明度の中央値を使用します。それ以外の場合、暗い/明るい画像は同じであると想定され、明るさが変化した画像を検出することができます。
  • fast 計算が必要な場合は、bool[]またはList<bool>を使用します。メモリを節約する必要がある多くのハッシュを保存する必要がある場合は、Bitarrayを使用します。少し格納されません、 byte
71
fubo

2つの画像を比較するアルゴリズム をチェックして、画像比較に利用可能な方法を確認できます。

完全なアルゴリズムを自分で再作成する場合を除き、既存のライブラリまたはそのコードの最小限の部分を使用してみてください(ライセンスが問題ない限り)。

エッジ検出および関連するコンピュータービジョンアルゴリズムのオープンソースC#実装の場合、OpenCVのラッパーである EmguCV を試すことができます。

7
Fab

画像を一般的な解像度にリサンプリングした後、ウェーブレット分解を使用して、画像自体の代わりにこの分解の係数を比較できます。最初のN個の係数のみを比較すると、この方法はノイズやその他のアーティファクトに対してより堅牢になります。

利用可能なウェーブレットのC#実装がいくつかあります。たとえば、 https://waveletstudio.codeplex.com/

4
Yurrit Avonds

興味深い質問ですが、画像の比較はそれほど難しくありませんが、

  1. これらの画像は同じです(最初の画像は2番目の画像のセクションではない、またはその逆)
  2. 画像は90度の倍数だけ回転します

比較を行う1つの方法は、

  1. 両方の画像のサイズを最小サイズに変更します
  2. 結果の白黒画像(または0と1の配列)の各画像にエッジ検出を適用します
  3. 結果のビットマップを比較し(最初のビットマップを保持し、2番目のビットマップを90度3回回転)、一致するピクセルの割合を計算し、最大値を取得します

ここで、値が90%などの妥当な値の範囲内にある場合(おそらく、いくつかの実験を行って決定する必要があります)、両方が同じであると安全に想定できますが、

  1. たとえ角で数ピクセル異なる場合でも、たとえば、2番目の画像が最初の画像から切り取られる
  2. 画像は90度の倍数以外で回転します(ただし、これはほとんどありません)
2