5.30. テンプレートマッチング¶
これまでに取り上げた検出器は、単一フレームの内容に関する問いに答えるものでした。ブロブがどこにあるか、線がどこへ向かうか、印刷されたコードが何を示しているか、といった問いです。これとは異なる種類の問いとして、ある画像を別の画像と比較するものがあります。キャプチャしたフレームのこの領域は、キャリブレーション時に保存した参照パッチに似ているか? マッチングメソッドはこの問いに答えます。
階調分析と統計分析では、関連する問い -- これら2つの同サイズの画像は全体としてどれくらい似ているか? -- に対して get_similarity() を紹介し、その基礎となる指標として SSIM を使いました。残るマッチングの問いは位置特定に関するものです。すなわち「これら2つの画像はどれくらい似ているか」ではなく「この大きな画像のどこにその小さなパッチが現れるか?」という問いです。位置特定の問いに適したツールがテンプレートマッチングです。
5.30.1. 基本的な呼び出し¶
find_template() は、小さなテンプレート画像がキャプチャしたフレーム内で最初に現れる場所を探します。実装では正規化相互相関(NCC)を使用します。テンプレートがフレーム上をスライドし、位置ごとのマッチスコアがテンプレートピクセルと背後のフレームピクセルとの相関から計算され(ゲインの変化にマッチが惑わされないよう、局所的な平均と分散に対して正規化されます)、スコアが threshold を超えた最初の位置がバウンディングボックスとして返されます。
template = image.Image("/sdcard/template.bmp", copy_to_fb=False)
template.to_grayscale()
match = img.find_template(template, threshold=0.7,
search=image.SEARCH_DS)
if match is not None:
img.draw_rectangle(match, color=(255, 0, 0))
このメソッドはグレースケール画像でのみ動作します。グレースケールでキャプチャするか(カラーセンサーを持たないカメラでは自然な選択です)、呼び出し前に to_grayscale() でその場で変換してください。同じことがディスクから読み込んだテンプレートにも当てはまります。カラーのテンプレートも同じメソッドで変換され、その結果がマッチャーの期待するものになります。
threshold は 0.0 から 1.0 までの浮動小数点数です。1.0 の値はピクセル単位での完全一致を要求し(実際にキャプチャした画像では決して起こりません)、0.0 は何でも受け入れ、0.6 から 0.8 の間の値は、テンプレートが似た照明条件でキャプチャされ、シーンが大きく変化していないという一般的なケースをカバーします。誤検出を抑えるにはしきい値を上げ、より多くの偽の一致と引き換えにノイズの多いマッチを受け入れるにはしきい値を下げます。
5.30.2. 探索戦略¶
search は2つの戦略のいずれかを選びます。image.SEARCH_EX は網羅的探索です。テンプレートがフレーム内のすべての step ピクセル位置をスライドし、しきい値を超えた最初のヒットを返します。image.SEARCH_DS はダイヤモンド探索です。マッチャーはまず粗くサンプリングし、その後最良スコアの周辺を絞り込みます。これは劇的に高速ですが、粗いパスがたまたまグローバル最大を上回る局所最大の近くに着地した場合、真のマッチを見逃す可能性があります。テンプレートが明確に定義され混同される可能性が低いリアルタイムパイプラインでは、SEARCH_DS が適切なデフォルトです。見逃しのコストが走査が遅くなるコストより高い一回限りのキャリブレーションでは、SEARCH_EX の方が安全です。
step は網羅的パス中のピクセルスキップを制御します(ダイヤモンド探索は独自のステップを管理します)。step の値を大きくすると、サブピクセル精度と引き換えに走査が高速化されます。roi は探索をフレームの一領域に制限し、マッチャーが考慮する範囲を狭めると同時に処理量を削減します。
戻り値は最良マッチを示す (x, y, w, h) のバウンディングボックスのタプル、またはどの位置もしきい値を超えなかった場合は None です。このバウンディングボックスは、次の処理段階のために draw_rectangle() や crop() にそのまま渡せます。
5.30.3. スケールと回転の落とし穴¶
テンプレートマッチングの古典的な落とし穴はスケールと回転への敏感さです。マッチャーはテンプレートをフレームとピクセル単位で比較します。ある距離でキャプチャしたテンプレートは、別の距離でキャプチャした同じ物体には一致せず、正面からキャプチャしたテンプレートは、斜めから見た同じ物体には一致しません。物体が人間の目には明らかに見えていても、しきい値はひそかにマッチングレベルを下回り、メソッドは None を返します。
単純なケースにはいくつかの回避策があります。アプリケーションは異なるスケールで複数のテンプレートをキャプチャし、各テンプレートに対して順番に find_template() を実行し、しきい値を超えた最初のものを採用することができます。コストはテンプレート数に比例します。また、マッチを実行する前に rotation_corr() や極座標変換(幾何変換)でフレームを前処理し、問題となる回転を取り除くこともできます。マッチさせるテンプレートは依然として補正後の形状に一致しなければなりません。
QA検査パイプラインに役立つイディオムは、テンプレートマッチャーを、階調分析と統計分析で紹介した類似度スコアラーと組み合わせるものです。find_template() がキャプチャしたフレーム内で部品を特定し、返されたバウンディングボックスを切り出して、参照パッチに対して get_similarity() に渡します。テンプレートマッチのステップが部品がどこにあるかを決め、類似度スコアのステップが部品が許容できるかどうかを決めます。この2つのステップは毎フレーム実行され、mean に対するしきい値が合否のゲートとなり、フレームに描き戻されたマッチしたバウンディングボックスが、オペレーターが見守る IDE プレビューになります。