蛇使いな彼女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の計算方法の紹介と式の変換など、統計学の基礎的な内容を含むお話でした。