Matlabのフーリエ領域でのテンプレートマッチングに苦労しています。これが私の画像です(アーティストはDeviantArtのRamalamaCreaturesです):
私の目的は、この例のように、ポッサムの耳の周りにバウンディングボックスを配置することです(normxcorr2を使用してテンプレートマッチングを実行しました)。
これが私が使用しているMatlabコードです:
clear all; close all;
template = rgb2gray(imread('possum_ear.jpg'));
background = rgb2gray(imread('possum.jpg'));
%% calculate padding
bx = size(background, 2);
by = size(background, 1);
tx = size(template, 2); % used for bbox placement
ty = size(template, 1);
%% fft
c = real(ifft2(fft2(background) .* fft2(template, by, bx)));
%% find peak correlation
[max_c, imax] = max(abs(c(:)));
[ypeak, xpeak] = find(c == max(c(:)));
figure; surf(c), shading flat; % plot correlation
%% display best match
hFig = figure;
hAx = axes;
position = [xpeak(1)-tx, ypeak(1)-ty, tx, ty];
imshow(background, 'Parent', hAx);
imrect(hAx, position);
コードが意図したとおりに機能していません。正しい領域を識別していません。これは失敗した結果です-間違った領域がボックスで囲まれています:
あなたが助けることができることを願っています!ありがとう。
コードで行っていることは、実際にはまったく相関関係ではありません。テンプレートを使用しており、入力画像で畳み込みを実行しています。フーリエ変換から思い出すと、2つの信号のスペクトルの乗算は、時間/空間領域での2つの信号の畳み込みに相当します。
基本的に、あなたがしていることは、テンプレートをカーネルとして使用し、それを使用して画像をフィルタリングすることです。次に、この出力の最大応答を見つけます。これが、テンプレートがあると見なされるものです。その領域が完全に白であるため、応答がボックス化されている場合は理にかなっています。完全に白の領域を持つカーネルとしてテンプレートを使用すると、非常に大きな応答が得られます。そのため、その領域が最大であると識別された可能性があります。応答。具体的には、領域には多くの高い値(〜255程度)があり、テンプレートパッチを使用して自然に畳み込みを実行します。この領域では、操作が加重和であるため、非常に大きな出力が得られます。そのため、画像の暗い領域でテンプレートを使用した場合、出力は小さくなります。テンプレートも暗いピクセルで構成されているため、これは誤りです。
ただし、フーリエ変換を使用してテンプレートの場所を特定することはできますが、代わりに 位相相関 を使用することをお勧めします。基本的に、2つのスペクトルの乗算を計算する代わりに、クロスパワースペクトルを計算します。周波数領域の2つの信号間のクロスパワースペクトルR
は、次のように定義されます。
出典: ウィキペディア
Ga
とGb
は周波数領域の元の画像とテンプレートであり、*
は共役です。 o
は、アダマール積または要素ごとの積として知られているものです。また、この分数の分子と分母の分割も要素ごとであることを指摘したいと思います。クロスパワースペクトルを使用して、絶対最大応答を生成する(x,y)
の場所をここで見つけた場合、これはテンプレートを背景画像に配置する必要がある場所です。
そのため、「相関」を計算するコード行を変更して、代わりにクロスパワースペクトルを計算する必要があります。しかし、私は非常に重要なことを指摘したいと思います。 normxcorr2
を実行すると、相関は画像の左上隅から始まります。テンプレートマッチングはこの場所から始まり、左上隅が原点であるテンプレートのサイズのウィンドウと比較されます。テンプレートの一致する場所を見つけるとき、その場所は一致したウィンドウの左上隅を基準にしています。 normxcorr2
を計算したら、従来、最大応答の行の半分と列の半分を追加して、中心の場所を見つけます。
FFT /周波数領域とのテンプレートマッチング(スライディングウィンドウ、相関など)に対してほぼ同じ操作を行っているため、この相関配列でピークを見つけ終えると、これも考慮に入れる必要があります。ただし、テンプレートが一致する場所の周りに長方形を描画するためのimrect
の呼び出しは、とにかく境界ボックスの左上隅を占めるため、ここでオフセットを行う必要はありません。そのため、そのコードを少し変更しますが、後でこのコードを使用して一致の中心位置を見つけたい場合は、オフセットロジックを念頭に置いてください。
再現可能になるように、StackOverflowから直接画像を読み込むようにコードも変更しました。
clear all; close all;
template = rgb2gray(imread('http://i.stack.imgur.com/6bTzT.jpg'));
background = rgb2gray(imread('http://i.stack.imgur.com/FXEy7.jpg'));
%% calculate padding
bx = size(background, 2);
by = size(background, 1);
tx = size(template, 2); % used for bbox placement
ty = size(template, 1);
%% fft
%c = real(ifft2(fft2(background) .* fft2(template, by, bx)));
%// Change - Compute the cross power spectrum
Ga = fft2(background);
Gb = fft2(template, by, bx);
c = real(ifft2((Ga.*conj(Gb))./abs(Ga.*conj(Gb))));
%% find peak correlation
[max_c, imax] = max(abs(c(:)));
[ypeak, xpeak] = find(c == max(c(:)));
figure; surf(c), shading flat; % plot correlation
%% display best match
hFig = figure;
hAx = axes;
%// New - no need to offset the coordinates anymore
%// xpeak and ypeak are already the top left corner of the matched window
position = [xpeak(1), ypeak(1), tx, ty];
imshow(background, 'Parent', hAx);
imrect(hAx, position);
これで、次の画像が表示されます。
クロスパワースペクトルの表面プロットを表示すると、次のようになります。
出力の残りの部分の応答が非常に小さい、明確に定義されたピークがあります。これは実際には位相相関のプロパティであるため、明らかに、最大値の場所が明確に定義されており、これがテンプレートの場所です。
お役に立てれば!