画像比較-高速アルゴリズム


393

私は画像のベーステーブルを作成し、新しい画像とそれを比較して、新しい画像がベースの正確な(または近い)複製であるかどうかを判断します。

たとえば、同じ画像の保存を数百回減らしたい場合は、その画像のコピーを1つ保存し、その画像への参照リンクを提供できます。新しい画像が入力されたら、既存の画像と比較して、重複していないことを確認したい...アイデアですか?

私のアイデアの1つは、小さなサムネイルに縮小してから、ランダムに100ピクセルの場所を選択して比較することでした。

回答:


459

この問題を解決する3つの方法を以下に示します(他にも多くの方法があります)。

  • 1つ目は、コンピュータビジョンの標準的なアプローチであるキーポイントマッチングです。これには、実装するための背景知識が必要になる場合があり、時間がかかる場合があります。

  • 2番目の方法は、基本的な画像処理のみを使用し、最初のアプローチよりも潜在的に高速で、実装が簡単です。ただし、理解しやすさは向上しますが、堅牢性に欠けます。スケーリング、回転、または変色した画像ではマッチングが失敗します。

  • 3番目の方法は高速で堅牢ですが、実装が最も難しい可能性があります。

キーポイントマッチング

100個のランダムなポイントを選択するよりも、100個の重要なポイントを選択するほうが優れています。画像の特定の部分には、他の部分よりも多くの情報があります(特にエッジとコーナー)。これらは、スマートな画像マッチングに使用したい部分です。Googleの「キーポイント抽出」と「キーポイントマッチング」を使用すると、このテーマに関するかなりの数の学術論文が見つかります。最近のSIFTキーポイントは、さまざまな縮尺、回転、照明の下で画像を照合できるため、間違いなく最も人気があります。いくつかのSIFT実装はここにあります

キーポイントマッチングの欠点の1つは、単純な実装の実行時間O(n ^ 2m)です。ここで、nは各画像のキーポイントの数、mはデータベースの画像の数です。四分木やバイナリスペースパーティショニングなど、一部の巧妙なアルゴリズムは、最も近い一致をより速く見つける場合があります。


代替ソリューション:ヒストグラム法

堅牢性は低くなりますが、速度が向上する可能性がある別のソリューションは、各画像の特徴ヒストグラムを作成し、ヒストグラムが入力画像のヒストグラムに最も近い画像を選択することです。これを学部生として実装し、3つのカラーヒストグラム(赤、緑、青)と2つのテクスチャヒストグラム、方向とスケールを使用しました。以下で詳細を説明しますが、これはデータベースの画像と非常によく似た画像を照合する場合にのみうまく機能したことに注意してください。再スケーリング、回転、または変色した画像はこの方法では失敗する可能性がありますが、トリミングなどの小さな変更によってアルゴリズムが壊れることはありません

カラーヒストグラムの計算は簡単です。ヒストグラムバケットの範囲を選択し、各範囲について、その範囲の色のピクセル数を集計します。たとえば、「緑」のヒストグラムを考えて、ヒストグラムに4つのバケットを選択するとします。0〜63、64〜127、128〜191、192〜255です。次に、ピクセルごとに緑の値を確認し、適切なバケットに集計を追加します。集計が完了したら、各バケットの合計を画像全体のピクセル数で割り、緑のチャネルの正規化されたヒストグラムを取得します。

テクスチャ方向ヒストグラムでは、画像のエッジ検出を開始することから始めました。各エッジポイントには、エッジに垂直な方向を指す法線ベクトルがあります。法線ベクトルの角度を0とPIの間の6つのバケットの1つに量子化しました(エッジには180度の対称性があるため、-PIと0の間の角度を0とPIの間になるように変換しました)。各方向のエッジポイントの数を集計すると、テクスチャの方向を表す非正規化ヒストグラムが得られます。ヒストグラムは、各バケットを画像内のエッジポイントの総数で割って正規化しました。

テクスチャスケールヒストグラムを計算するために、各エッジポイントについて、同じ方向で次に最も近いエッジポイントまでの距離を測定しました。たとえば、エッジポイントAの方向が45度の場合、アルゴリズムは45度の方向(または妥当な偏差内)の別のエッジポイントが見つかるまでその方向に歩きます。各エッジポイントのこの距離を計算した後、それらの値をヒストグラムにダンプし、エッジポイントの総数で除算して正規化します。

これで、画像ごとに5つのヒストグラムが作成されました。2つの画像を比較するには、各ヒストグラムバケット間の差の絶対値を取得してから、これらの値を合計します。たとえば、画像AとBを比較するには、

|A.green_histogram.bucket_1 - B.green_histogram.bucket_1| 

緑のヒストグラムの各バケットについて、他のヒストグラムについても繰り返し、すべての結果を合計します。結果が小さいほど、一致率は高くなります。データベース内のすべての画像について繰り返し、最小の結果との一致が勝ちます。しきい値が必要な場合があります。しきい値を超えると、アルゴリズムは一致が見つからなかったと結論付けます。


3番目の選択-キーポイント+決定木

おそらく他の2つよりもはるかに高速な3番目のアプローチは、セマンティックテキストンフォレスト(PDF)を使用することです。これには、単純なキーポイントを抽出し、コレクション決定ツリーを使用して画像を分類することが含まれます。これは、コストのかかるマッチングプロセスを回避するため、単純なSIFTキーポイントマッチングよりも高速であり、キーポイントはSIFTよりもはるかに単純であるため、キーポイントの抽出がはるかに高速です。ただし、SIFTメソッドの回転、スケール、ライティングに対する不変性は維持されます。これは、ヒストグラムメソッドにはなかった重要な機能です。

更新

私の間違い-Semantic Texton Forestsの論文は、具体的にはイメージマッチングではなく、領域のラ​​ベル付けに関するものです。マッチングを行う元の論文は次のとおり です。ランダム化ツリーを使用したキーポイント認識。また、以下の論文は引き続きアイデアを発展させ、最先端の技術を表現しています(c。2010)。


ヒストグラムアプローチが最も理にかなっているようです。私はあなたが(4と同じ画像を処理する)イメージが変わったために比較されているだけの場合にはすべての面でこれを実行するには、画像を回転させることができますと仮定している-のおかげで
ミード

4
@meadeそうです。他に考慮すべきこと:問題によっては、アルゴリズムで5つのヒストグラムすべてを使用する必要がない場合があります。テクスチャ方向ヒストグラムを破棄すると、画像の回転バージョンを一致させることができます。テクスチャスケールヒストグラムを破棄すると、画像の再スケーリングされたバージョンを一致させることができます。類似性を比較する機能がいくらか失われますが、状況によってはこれは問題にならない場合があります。また、テクスチャ情報の計算はアルゴリズムの最もコストのかかる部分であるため、アルゴリズムも高速になります。
Kyle Simek、

@redmoskito:質問があります。たとえば、緑のヒストグラムの数値をどのように取得しますか?だから、他の画像ヒストグラムでそれを引くことができますか?緑のヒストグラムがあり、3ピクセルが0〜63バケットに属し、5ピクセルが64〜127に属しているとします。値はどれですか?
動的

3
@Ikasoまったく同じ画像の場合、おそらくそのようなものを使用したくないので、単純なCRCまたはMD5比較の使用を検討してください。単一のピクセルが異なる場合やメタデータが変更された場合など、これで十分でない場合は、ヒストグラム法でも十分です。画像が同じでも回転またはスケーリングされている場合、ヒストグラムベースの方法で十分な場合がありますが、失敗する可能性があります。画像の色が変わった場合は、関心点ベースのアルゴリズムを使用する必要があります。
reox 2013年

5
今日付け加えたいのは、いくつか例を挙げると、FAST検出器やバイナリ記述子(BRIEF、BRISK、ORB、FREAK、BinBoost)など、SIFTに代わる多くの高速な代替手段が存在するということです。バイナリ記述子のチュートリアルでは、ここで見つけることができます: gilscvblog.wordpress.com/2013/08/26/...
GilLevi

85

私が知っている最良の方法は、知覚ハッシュを使用することです。そのようなハッシュの良いオープンソース実装が次の場所で利用可能であるように見えます:

http://phash.org/

主なアイデアは、元の画像ファイルの顕著な特徴を特定し、それらの特徴のコンパクトな表現をハッシュすることにより(画像データを直接ハッシュするのではなく)、各画像を小さなハッシュコードまたは「フィンガープリント」に縮小することです。これは、画像を小さな拇印サイズの画像に減らし、拇印を比較するなどの単純なアプローチよりも、誤検知率が大幅に低下することを意味します。

phashはいくつかのタイプのハッシュを提供し、画像、オーディオ、またはビデオに使用できます。


リンクでのObjective-C知覚ハッシュ実現を見つけることができるこの方法で興味深い誰だgithub.com/ameingast/cocoaimagehashing
アレクセイVoitenko

@AlexeyVoitenkoこれは、デフォルトの構成でphash.orgによって生成されたハッシュと互換性がありますか?
マイケル

1
私の経験では、phashは同じ画像の異なるサイズを見つけるのに適していますが、類似する画像​​には適していません。たとえば、同じオブジェクトの2つの異なる写真のハッシュは非常に異なる場合があります。
レナ

39

この投稿は私の解決策の出発点であり、ここには多くの良いアイデアがあるので、結果を共有します。主な洞察は、phashの速度を利用して、キーポイントベースの画像マッチングの遅さを回避する方法を見つけたということです。

一般的な解決策として、いくつかの戦略を採用するのが最善です。各アルゴリズムは特定のタイプの画像変換に最適であり、それを利用できます。

一番上は最速のアルゴリズムです。一番下が最も遅い(より正確ですが)。速いレベルで良い一致が見つかった場合、遅いものをスキップすることがあります。

  • 完全に重複するファイルハッシュベース(md5、sha1など)
  • 再スケーリングされた画像の知覚ハッシュ(phash)
  • 変更された画像の機能ベース(SIFT)

私はphashで非常に良い結果を得ています。精度は、再スケーリングされた画像に適しています。(知覚的に)変更されたイメージ(トリミング、回転、ミラーリングなど)には適していません。ハッシング速度に対処するには、ディスクキャッシュ/データベースを使用して、干し草のハッシュを維持する必要があります。

phashの本当に良い点は、ハッシュデータベース(私にとっては約1000画像/秒)を構築すると、特にハッシュデータベース全体をメモリに保持できる場合、検索が非常に高速になることです。ハッシュは8バイトしかないため、これはかなり実用的です。

たとえば、100万の画像がある場合、100万の64ビットハッシュ値(8 MB)の配列が必要になります。一部のCPUでは、これはL2 / L3キャッシュに適合します。実際の使用では、1ギガハーム/秒以上のcorei7比較を確認しました。これは、CPUに対するメモリ帯域幅の問題にすぎません。10億画像データベースは、64ビットCPU(8GB RAMが必要)で実用的であり、検索は1秒を超えません。

変更/トリミングされた画像の場合、SIFTのような変換不変の機能/キーポイント検出器が適しています。SIFTは、クロップ/回転/ミラーなどを検出する適切なキーポイントを生成します。ただし、記述子の比較は、phashで使用されるハミング距離に比べて非常に遅くなります。これは大きな制限です。1つの画像を検索するためのIxJxK記述子の比較には最大数があるため(I = num干し草の画像、J =干し草の画像あたりのターゲットキーポイント、K =針の画像あたりのターゲットキーポイント)、多数の比較が行われます。

速度の問題を回避するために、検出された各キーポイントの周りにphashを使用し、フィーチャのサイズ/半径を使用してサブ長方形を決定しました。これをうまく機能させる秘訣は、半径を拡大/縮小して、(針の画像上に)異なるサブ矩形レベルを生成することです。通常、最初のレベル(スケールなし)は一致しますが、多くの場合、さらにいくつかかかります。なぜこれが機能するのかは100%わかりませんが、phashが機能するには小さすぎる機能を有効にできると想像できます(phashは画像を32x32に縮小します)。

別の問題は、SIFTがキーポイントを最適に分散しないことです。エッジの多い画像のセクションがある場合、キーポイントはそこでクラスター化し、別の領域には何も表示されません。OpenCVでGridAdaptedFeatureDetectorを使用して、分布を改善しています。どのグリッドサイズが最適かわからないので、小さなグリッド(画像の向きに応じて1x3または3x1)を使用しています。

機能検出の前に、すべての干し草の画像(および針)をより小さいサイズにスケーリングする必要があります(私は最大サイズで210pxを使用しています)。これにより、画像内のノイズが減少し(常にコンピュータービジョンアルゴリズムの問​​題)、検出器の焦点がより目立つ機能になります。

人の画像の場合、顔検出を試してみて、拡大縮小する画像のサイズとグリッドサイズを決定することができます(たとえば、最大の顔が100pxに拡大縮小される)。機能検出器は(ピラミッドを使用して)複数のスケールレベルを考慮しますが、使用するレベル数には制限があります(これはもちろん調整可能です)。

キーポイント検出器は、必要な機能の数よりも少ない数を返す場合におそらく最もよく機能します。たとえば、400を要求して300を取り戻す場合、それは良いことです。毎回400を返す場合、おそらくいくつかの優れた機能を除外する必要がありました。

針の画像は干し草の画像よりもキーポイントが少なくても、良い結果が得られます。さらに追加しても、必ずしも大きな利益が得られるわけではありません。たとえば、J = 400とK = 40の場合、ヒット率は約92%です。J = 400とK = 400の場合、ヒット率は96%まで上昇します。

ハミング機能の極端な速度を利用して、スケーリング、回転、ミラーリングなどを解くことができます。マルチパス手法を使用できます。各反復で、サブ長方形を変換し、再度ハッシュして、検索関数を再度実行します。


8

Cartmanが指摘したように、正確な重複を見つけるために、あらゆる種類のハッシュ値を使用できます。

近い画像を見つけるための出発点の1つはここにあります。これは、CG企業が使用するツールであり、改良された画像が依然として本質的に同じシーンを示しているかどうかを確認します。


7

私はアイデアを持っています。それはうまくいくことができ、それは非常に速くなる可能性が最も高いです。画像をサブサンプリングして80x60の解像度または同等の解像度を指定し、グレースケールに変換することができます(サブサンプリング後に高速になります)。比較する両方の画像を処理します。次に、2つの画像(クエリ画像とdbからのそれぞれ)間の差の2乗の正規化された合計を実行します。または、両方の画像が類似している場合は、応答を1に近づけるさらに優れた正規化相互相関を実行します。次に、画像が類似している場合は、より高度な手法に進んで、同じ画像であることを確認できます。明らかに、このアルゴリズムはデータベース内の画像の数に関して線形であるため、最新のハードウェアでは1秒あたり最大10000画像まで非常に高速になります。回転に対する不変性が必要な場合は、この小さな画像に対して支配的な勾配を計算できます。そして、座標系全体を標準的な向きに回転させることができますが、これは遅くなります。そして、いいえ、ここでスケーリングするための不変性はありません。

より一般的なものが必要な場合、または大きなデータベース(数百万の画像)を使用する場合は、画像検索理論を検討する必要があります(過去5年間に大量の論文が発表されました)。他の答えにはいくつかの指針があります。しかし、それはやり過ぎかもしれません。提案ヒストグラムアプローチで十分です。多くの異なる高速なアプローチを組み合わせるとさらに良いと思いますが。


7

私の会社では、毎月2400万枚の画像がメーカーから入っています。私がカタログにアップロードした画像が新しい画像であることを確認するための高速なソリューションを探していました。

私は、理想的な解決策を見つけるためにインターネットを広範囲に検索したと言いたいです。独自のエッジ検出アルゴリズムも開発しました。
複数のモデルの速度と精度を評価しました。背景が白の私の画像は、フェージングで非常にうまく機能します。同様redcalxが言った、私はphashまたはahashをお勧めします。MD5ハッシュやその他の暗号化ハッシュを使用しないでください。正確に一致する画像のみが必要な場合を除きます。画像間で発生するサイズ変更や操作は、異なるハッシュになります。

phash / ahashについては、こちらをご覧ください:imagehash

私のコードと正確さを投稿して、* redcalxの投稿を拡張したかったのです。

私がやること:

from PIL import Image
from PIL import ImageFilter
import imagehash

img1=Image.open(r"C:\yourlocation")
img2=Image.open(r"C:\yourlocation")
if img1.width<img2.width:
    img2=img2.resize((img1.width,img1.height))
else:
    img1=img1.resize((img2.width,img2.height))
img1=img1.filter(ImageFilter.BoxBlur(radius=3))
img2=img2.filter(ImageFilter.BoxBlur(radius=3))
phashvalue=imagehash.phash(img1)-imagehash.phash(img2)
ahashvalue=imagehash.average_hash(img1)-imagehash.average_hash(img2)
totalaccuracy=phashvalue+ahashvalue

これが私の結果の一部です。

item1  item2  totalsimilarity
desk1  desk1       3
desk1  phone1     22
chair1 desk1      17
phone1 chair1     34

お役に立てれば!


6

画像のサイズをほぼアイコンのサイズ、たとえば48x48に落とし、次にグレースケールに変換してから、ピクセル間の差分、つまりデルタを取るとうまくいくと思います。実際のピクセルカラーではなく、ピクセルカラーの変化を比較しているため、画像が少し明るいか暗いかは関係ありません。ピクセルが明るすぎたり暗すぎたりすると失われるため、大きな変更が重要になります。これを1行に適用することも、精度を上げるために必要なだけ適用することもできます。比較可能なキーを形成するために、最大で47x47 = 2,209の減算を行う必要があります。


3

100個のランダムな点を選択すると、類似した(場合によっては類似しない)画像が同じものとしてマークされますが、これはあなたが望むものではないと思います。画像が異なる形式(png、jpegなど)であるか、サイズが異なるか、メタデータが異なる場合、MD5ハッシュは機能しません。すべての画像を小さいサイズに縮小することは良い策です。適切な画像ライブラリ/高速言語を使用していて、サイズが十分に小さい限り、ピクセルごとの比較を実行するのにそれほど時間がかかりません。

あなたはそれらを小さくすることを試みることができます、そしてそれらが同じであれば、より大きいサイズで別の比較を実行します-速度と正確さの良い組み合わせかもしれません...


正確な重複を探しているがフォーマット/メタデータが異なる場合は、実際のピクセル値のハッシュ(MD5など)を実行できます。Imagemagickはこれを署名と呼びます(暗号署名とは関係ありません)。最初にそれを減らすこともできます。たとえば、JPEGアーティファクトの影響を減らすためにピクセルあたり4ビットに切り捨てるか、グレースケールに変換してわずかに色が変更された画像に一致させます。
レナ

2

多数の画像がある場合は、確率的で効率的な結果を得るために複数のハッシュを使用するブルームフィルターを調べます。画像の数が多くない場合は、md5のような暗号化ハッシュで十分です。


つまり、(ブルームフィルターを理解しようとする)-それは、ベースイメージ上のランダムなピクセルポイントを選択し、ランダムにピクセルの赤/緑/青の値を取得することを意味します-次に、新しいイメージと比較しますか?次に、確率レベル(90%一致)を使用して、2つの画像がどの程度類似しているかを判断しますか?
2009年

5
これは類似性チェックではなく、同等性チェックです。類似性が必要な場合、ハッシュは適切なアプローチではありません。ブルームの背後にあるアイデアは、複数のハッシュアルゴリズムを使用して一意の識別の可能性を高めることです。ランダムなポイントを選択することは、毎回異なる結果をもたらすため、ハッシュアルゴリズムの最良のアプローチではありません。
jdigital 2009年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.