蛇使いな彼女BLOG
【第105回】輝度とパターンマッチング③~結果の参照~
2024.05.17

皆さんこんにちは!前回はZNCCのと計算方法を説明したので、今回は実際に2つの計算結果を比較してみましょう。
[方法1].
#入力画像とテンプレートの用意
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
temp=gray[195:280,55:168]
# 走査窓毎にテンプレートとの相関係数を計算①
def scanning_window(img,temp):
h,w=img.shape
hi,wi=temp.shape
img = np.array(img, dtype="float")
temp = np.array(temp, dtype="float")
#テンプレートのセンタリング
t_mean=np.mean(temp)
T=temp-t_mean
#計算結果を書き込む配列
res= np.tile(0,(h-hi, w-wi))
for dy in range(0,h-hi):
for dx in range(0,w-wi):
win=img[dy:dy+hi,dx:dx+wi]
w_mean=np.mean(win)
#走査窓のセンタリング
W=win-w_mean
#ZNCC
Mol=np.sum(W*T)
Den=np.sqrt(np.sum(W**2))*np.sqrt(np.sum(T**2))
ZNCC=Mol/Den
try:
res[dy,dx]=ZNCC
except ZeroDivisionError:
res[dy,dx]=0
return res
score=scanning_window(gray,temp)
r,c=np.unravel_index(np.argmax(score), score.shape)
>>> print(r,c) 195 55 >>>
最初の段階でテンプレートは入力画像[195:280,55:168]の位置に指定したことから、バッチリ成功していますね!
[方法2].
続いてもう一つの方法です。
#入力画像とテンプレートの用意
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
temp=gray[195:280,55:168]
# 走査窓毎にテンプレートとの相関係数を計算②
def scanning_window2(img,temp):
h,w=img.shape
hi,wi=temp.shape
img = np.array(img, dtype="float")
temp = np.array(temp, dtype="float")
res= np.tile(0,(h-hi, w-wi))
for dy in range(0,h-hi):
for dx in range(0,w-wi):
win=img[dy:dy+hi,dx:dx+wi]
#以下ZNCCの計算
#分散V
V=np.mean(win**2)-(np.mean(win))**2
V2=np.mean(temp**2)-(np.mean(temp))**2
#分散V=標準偏差Sの2乗
S=np.sqrt(V)*np.sqrt(V2)
#共分散Cov
Cov=np.mean((win-np.mean(win))*(temp-np.mean(temp)))
ZNCC=Cov/S
try:
res[dy,dx]=ZNCC
except ZeroDivisionError:
res[dy,dx]=0
return res
score=scanning_window2(gray,temp)
r,c=np.unravel_index(np.argmax(score), score.shape)
>>> print(r,c) 0 0 >>>
[方法2].は計算結果が全て0になってしまったようです。
r、cは最も大きなZNCC値を持つ走査位置の行番号、列番号を示しますが、一番初期の(0,0)位置になっています。しかも、もう一点指摘すると前回の記事では今使ったテンプレートと全く同じ位置と走査位置(0,0)のZNCCは算出しましたよね。その結果は約「0.0511」だったはずですが
>>> score[r,c] 0 >>>
このように0に丸められてしまっています・・・(°°;) これは何かがおかしい。
後でじっくりとコードを確認したんですが、桁落ちやアンダーフローではなく、単純に計算結果を格納する配列をnp.tileで指定していたことに問題がありました!!!(笑)
np.tileは初期値から上書きする際、整数型しか受付てくれないのでそりゃ全部0になるよね~('_')
ということで、以下の記述を
#計算結果を書き込む配列
res= np.tile(0,(h-hi, w-wi))
↓こっちに直してみたところ、[方法1]と[方法2]、どちらをとっても上手く正解へ導くことが出来ました✨
res= np.empty((h-hi, w-wi))
皆さま、毎度モトハシの凡ミスでご迷惑お掛けしております(*_*)
上記の[方法1]で結果が上手く出たのは、たまたま計算結果が1になったからだと考察しています・・・。(運がよかったので間違いに気づきませんでした)
気を取り直して、結果を画像として表示するとこのようになります。
ZNCCによるテンプレートマッチング結果


上図はZNCCで最も類似する位置に囲みをいれたもの。下図はZNCCの結果をマッピングしたもの。
完全一致の場所が赤く示されているのは当然ですが、テンプレートと同じ布地に対して類似度はほぼ0で、なぜかチョコの毛並み部分で若干数値が高いのは興味深いですね。
今回はZNCCの計算方法の紹介と式の変換など、統計学の基礎的な内容を含むお話でした。

06-6657-5130
sales@hydrolab.co.jp