47

私は画像を互いに比較して、それらが異なるかどうかを調べようとしています。最初に、RGB値のピアソン相関を作成しようとしました。これは、画像が少しずれていない限り、非常にうまく機能します。したがって、100%同一の画像があり、1つが少し移動している場合、相関値が正しくありません。

より良いアルゴリズムのための提案はありますか?

ところで、私は何千もの画像を比較することについて話している...

編集:これが私の写真の例です(顕微鏡):

im1:

ここに画像の説明を入力してください

im2:

ここに画像の説明を入力してください

im3:

ここに画像の説明を入力してください

im1とim2は同じですが、少しシフト/カットされているため、im3は完全に異なるものとして認識されます...

編集: 問題はピーターハンセンの提案で解決されます!非常にうまく機能します!すべての回答に感謝します!いくつかの結果はここで見つけることができます http://labtools.ipk-gatersleben.de/image%20comparison/image%20comparision.pdf

4

9 に答える 9

38

同様の質問が 1 年前に行われ、多数の回答が寄せられました。その中には、画像のピクセル化に関するものも含まれていました。これは、少なくとも事前資格認定のステップとして提案するつもりでした (非常に似ていない画像を非常に迅速に除外するため)。

さらに多くの参照と適切な回答がある、まだ以前の質問へのリンクもあります。

上記の 3 つの画像 (それぞれ im1.jpg、im2.jpg、im3.jpg として保存) を使用して、Scipy のいくつかのアイデアを使用した実装を次に示します。最終的な出力は、ベースラインとして im1 をそれ自体と比較した後、各画像を他の画像と比較したものです。

>>> import scipy as sp
>>> from scipy.misc import imread
>>> from scipy.signal.signaltools import correlate2d as c2d
>>>
>>> def get(i):
...     # get JPG image as Scipy array, RGB (3 layer)
...     data = imread('im%s.jpg' % i)
...     # convert to grey-scale using W3C luminance calc
...     data = sp.inner(data, [299, 587, 114]) / 1000.0
...     # normalize per http://en.wikipedia.org/wiki/Cross-correlation
...     return (data - data.mean()) / data.std()
...
>>> im1 = get(1)
>>> im2 = get(2)
>>> im3 = get(3)
>>> im1.shape
(105, 401)
>>> im2.shape
(109, 373)
>>> im3.shape
(121, 457)
>>> c11 = c2d(im1, im1, mode='same')  # baseline
>>> c12 = c2d(im1, im2, mode='same')
>>> c13 = c2d(im1, im3, mode='same')
>>> c23 = c2d(im2, im3, mode='same')
>>> c11.max(), c12.max(), c13.max(), c23.max()
(42105.00000000259, 39898.103896795357, 16482.883608327804, 15873.465425120798)

そのため、im1 をそれ自体と比較すると 42105 のスコアが得られることに注意してください。im2 を im1 と比較してもそれほど大きくはありませんが、im3 を他のいずれかと比較すると、その値の半分をはるかに下回ります。これがどの程度うまく機能し、どのように改善できるかを確認するには、他の画像を試してみる必要があります。

実行時間は長いです...私のマシンでは数分です。おそらく、他の質問への回答で言及されている「jpgファイルサイズの比較」トリック、またはピクセル化を使用して、非常に異なる画像を比較する時間を無駄にしないように、事前フィルタリングを試みます。さまざまなサイズの画像があるという事実は事態を複雑にしますが、予想される屠殺の程度について十分な情報を提供していないため、それを考慮に入れた具体的な回答を提供することは困難です.

于 2009-11-30T18:51:30.603 に答える
13

画像ヒストグラム比較でこれを行ったことがあります。私の基本的なアルゴリズムはこれでした:

  1. 画像を赤、緑、青に分割
  2. 赤、緑、青のチャネルの正規化されたヒストグラムを作成し、それらをベクトルに連結します(r0...rn, g0...gn, b0...bn)。ここで、n は「バケット」の数で、256 で十分です。
  3. このヒストグラムを別の画像のヒストグラムから引き、距離を計算します

ここにいくつかのコードがnumpyありますpil

r = numpy.asarray(im.convert( "RGB", (1,0,0,0, 1,0,0,0, 1,0,0,0) ))
g = numpy.asarray(im.convert( "RGB", (0,1,0,0, 0,1,0,0, 0,1,0,0) ))
b = numpy.asarray(im.convert( "RGB", (0,0,1,0, 0,0,1,0, 0,0,1,0) ))
hr, h_bins = numpy.histogram(r, bins=256, new=True, normed=True)
hg, h_bins = numpy.histogram(g, bins=256, new=True, normed=True)
hb, h_bins = numpy.histogram(b, bins=256, new=True, normed=True)
hist = numpy.array([hr, hg, hb]).ravel()

2 つのヒストグラムがある場合、次のように距離を取得できます。

diff = hist1 - hist2
distance = numpy.sqrt(numpy.dot(diff, diff))

2 つの画像が同一の場合、距離は 0 であり、発散するほど距離が大きくなります。

私にとっては写真には非常にうまく機能しましたが、テキストやロゴなどのグラフィックスには失敗しました.

于 2009-11-30T11:27:37.520 に答える
6

問題をより明確にする必要がありますが、これらの 5 つの画像を見ると、生物はすべて同じ方向を向いているように見えます。これが常に当てはまる場合は、2 つの画像間で正規化された相互相関を行い、ピーク値を類似度として取得してみてください。Python の正規化された相互相関関数については知りませんが、同様のfftconvolve()関数があり、循環相互相関を自分で行うことができます。

a = asarray(Image.open('c603225337.jpg').convert('L'))
b = asarray(Image.open('9b78f22f42.jpg').convert('L'))
f1 = rfftn(a)
f2 = rfftn(b)
g =  f1 * f2
c = irfftn(g)

画像のサイズが異なり、出力が重み付けまたは正規化されていないため、これは記述どおりには機能しません。

出力のピーク値の位置は 2 つの画像間のオフセットを示し、ピークの大きさは類似性を示します。良い一致と悪い一致の違いを区別できるように、重み付け/正規化する方法が必要です。

まだ正規化する方法がわからないので、これは私が望むほど良い答えではありませんが、わかったら更新します。調査するアイデアが得られます。

于 2009-12-04T19:05:27.003 に答える
6

問題がシフトされたピクセルに関するものである場合は、周波数変換と比較する必要があります。

FFT は問題ないはずですが ( numpy には 2D 行列の実装があります)、この種のタスクには Wavelets の方が優れているといつも聞いています ^_^

パフォーマンスについては、すべての画像が同じサイズの場合、よく覚えていれば、FFTW パッケージは FFT 入力サイズごとに専用の関数を作成したため、同じコードを再利用してパフォーマンスを大幅に向上させることができます... numpy が FFTW に基づいているかどうかはわかりませんが、そうでない場合は、そこで少し調査してみてください。

ここにプロトタイプがあります...少し試してみて、どのしきい値が画像に適合するかを確認してください。

import Image
import numpy
import sys

def main():
    img1 = Image.open(sys.argv[1])
    img2 = Image.open(sys.argv[2])

    if img1.size != img2.size or img1.getbands() != img2.getbands():
        return -1

    s = 0
    for band_index, band in enumerate(img1.getbands()):
        m1 = numpy.fft.fft2(numpy.array([p[band_index] for p in img1.getdata()]).reshape(*img1.size))
        m2 = numpy.fft.fft2(numpy.array([p[band_index] for p in img2.getdata()]).reshape(*img2.size))
        s += numpy.sum(numpy.abs(m1-m2))
    print s

if __name__ == "__main__":
    sys.exit(main())

もう 1 つの方法は、画像をぼかしてから、2 つの画像からピクセル値を減算することです。差がゼロでない場合は、画像の 1 つを各方向に 1 px シフトして再度比較できます。差が前のステップよりも小さい場合は、グラデーションの方向にシフトして差がなくなるまで減算を繰り返すことができます。特定のしきい値を下回るか、再び増加します。ぼかしカーネルの半径が画像のシフトよりも大きい場合、これは機能するはずです。

また、 Pano Toolsなど、写真のワークフローで複数の露出をブレンドしたり、パノラマを作成したりするために一般的に使用されるツールのいくつかを試してみることもできます。

于 2009-11-30T11:14:10.060 に答える
2

私はずっと前にいくつかの画像処理コースを受講しましたが、マッチングを行うときは通常、画像をグレースケールにしてから、画像のエッジをシャープにしてエッジだけが見えるようにしたことを覚えています。あなた (ソフトウェア) は、差が最小になるまで画像をシフトして差し引くことができます。

その差が設定したしきい値よりも大きい場合、画像は等しくなく、次の画像に進むことができます。次に、しきい値が小さい画像を分析できます。

せいぜい、可能な一致を根本的に間引くことができると思いますが、可能な一致を個人的に比較して、それらが本当に等しいかどうかを判断する必要があります。

昔のようにコードを実際に示すことはできません。そのコースでは Khoros/Cantata を使用しました。

于 2009-11-30T15:12:42.933 に答える
1

まず第一に、相関は非常に CPU を集中的に使用するため、類似性を測るには不正確な尺度です。個々のピクセル間の差がある場合は、単に二乗和を求めてみませんか?

最大シフトが制限されている場合の簡単な解決策: 考えられるすべてのシフトされた画像を生成し、最適な画像を見つけます。シフトされたすべての画像で一致できるピクセルのサブセットに対してのみ、一致変数 (つまり相関) を計算するようにしてください。また、最大シフトは画像のサイズよりも大幅に小さくする必要があります。

より高度な画像処理技術を使用したい場合は、 SIFTを参照することをお勧めします。これは、平行移動、回転、およびスケールに関係なく、(理論的には) 画像内のアイテムを適切に一致させることができる非常に強力な方法です。

于 2009-11-30T12:27:13.220 に答える
0

次のようなことができると思います:

  • 参照画像と比較画像の縦横のずれを推定します。モーションベクトルを使用した単純なSAD(絶対差の合計)で十分です。

  • それに応じて比較画像をシフトします

  • あなたがやろうとしていたピアソン相関を計算します

シフト測定は難しくありません。

  • 比較画像で領域 (約 32x32) を取得します。
  • 水平方向に x ピクセル、垂直方向に y ピクセルだけシフトします。
  • SAD (絶対差の合計) wrt 元の画像を計算します。
  • 小さい範囲 (-10、+10) の x と y のいくつかの値に対してこれを行います。
  • 差が最小になる場所を見つける
  • その値をシフト モーション ベクトルとして選択します

ノート:

x と y のすべての値で SAD が非常に高くなる場合は、画像が非常に似ていないため、シフト測定は必要ないと想定できます。

于 2009-11-30T11:21:26.820 に答える