OpenCV 5.0.0
Open Source Computer Vision
読み込み中...
検索中...
見つかりません
🤖 AIによる機械翻訳(非公式) — これは OpenCV 5.0.0 公式リファレンス(英語)を AI (Claude) で自動翻訳したものです。訳に誤りを含む場合があります。正確な情報は 公式英語版(原文) を参照してください。
テンプレートマッチング

前のチュートリアル: バックプロジェクション
次のチュートリアル: 画像中の輪郭の検出

原著者Ana Huamán
互換性OpenCV >= 3.0

目的

このチュートリアルでは、以下の方法を学ぶ:

  • OpenCVの関数 matchTemplate() を使い、画像パッチと入力画像との間でマッチを探索する
  • OpenCVの関数 minMaxLoc() を使い、与えられた配列の最大値と最小値(およびその位置)を求める。

理論

テンプレートマッチングとは何か?

テンプレートマッチングは、テンプレート画像(パッチ)にマッチする(類似する)画像の領域を見つける手法である。

パッチは矩形でなければならないが、その矩形のすべてが意味を持つとは限らない。そのような場合、マスクを使ってマッチの探索に利用すべきパッチの部分だけを切り出すことができる。

どのように動作するのか?

  • 主に2つの要素が必要である:

    1. 元画像 (I): テンプレート画像とのマッチが見つかると期待される画像
    2. テンプレート画像 (T): 元画像と比較されるパッチ画像

    目的は、最もよくマッチする領域を検出することである:

  • マッチする領域を特定するには、テンプレート画像を元画像上でスライドさせながら比較しなければならない:
  • スライドとは、パッチを1ピクセルずつ(左から右、上から下へ)移動させることを意味する。各位置で、その位置でのマッチがどれだけ「良い」か「悪い」か(つまりパッチが元画像のその領域とどれだけ類似しているか)を表す指標が計算される。
  • I 上の T の各位置について、その指標を結果行列 R格納する。R 内の各位置 \((x,y)\) はマッチの指標を持つ:

上の画像は、指標 TM_CCORR_NORMED でパッチをスライドさせた結果 R である。最も明るい位置が最も高いマッチを示す。見て取れるように、赤い丸で示された位置がおそらく最も高い値を持つ位置であり、その位置(その点を角とし、幅と高さがパッチ画像に等しい矩形)がマッチとみなされる。

  • 実際には、関数 minMaxLoc() を使って R 行列の中の最大値(マッチング手法の種類によっては最小値)を見つける。

マスクはどのように機能するのか?

  • If masking is needed for the match, three components are required:
    1. 元画像 (I): テンプレート画像とのマッチが見つかると期待される画像
    2. テンプレート画像 (T): 元画像と比較されるパッチ画像
    3. マスク画像 (M): テンプレートをマスクするグレースケール画像であるマスク
  • 現在マスクを受け付けるマッチング手法は2つだけである: TM_SQDIFF と TM_CCORR_NORMED(OpenCVで利用できるすべてのマッチング手法の説明は下記参照)。
  • マスクはテンプレートと同じ寸法でなければならない
  • マスクは CV_8U または CV_32F のビット深度を持ち、テンプレート画像と同じチャンネル数でなければならない。CV_8U の場合、マスク値は2値、すなわちゼロと非ゼロとして扱われる。CV_32F の場合、値は [0..1] の範囲に収まる必要があり、テンプレートのピクセルは対応するマスクのピクセル値と乗算される。このサンプルの入力画像は CV_8UC3 型なので、マスクもカラー画像として読み込まれる。

OpenCVで利用できるマッチング手法は何か?

よい質問である。OpenCVはテンプレートマッチングを関数 matchTemplate() で実装している。利用できる手法は6つある:

  1. method=TM_SQDIFF

    \[R(x,y)= \sum _{x',y'} (T(x',y')-I(x+x',y+y'))^2\]

  2. method=TM_SQDIFF_NORMED

    \[R(x,y)= \frac{\sum_{x',y'} (T(x',y')-I(x+x',y+y'))^2}{\sqrt{\sum_{x',y'}T(x',y')^2 \cdot \sum_{x',y'} I(x+x',y+y')^2}}\]

  3. method=TM_CCORR

    \[R(x,y)= \sum _{x',y'} (T(x',y') \cdot I(x+x',y+y'))\]

  4. method=TM_CCORR_NORMED

    \[R(x,y)= \frac{\sum_{x',y'} (T(x',y') \cdot I(x+x',y+y'))}{\sqrt{\sum_{x',y'}T(x',y')^2 \cdot \sum_{x',y'} I(x+x',y+y')^2}}\]

  5. method=TM_CCOEFF

    \[R(x,y)= \sum _{x',y'} (T'(x',y') \cdot I'(x+x',y+y'))\]

    ここで

    \[\begin{array}{l} T'(x',y')=T(x',y') - 1/(w \cdot h) \cdot \sum _{x'',y''} T(x'',y'') \\ I'(x+x',y+y')=I(x+x',y+y') - 1/(w \cdot h) \cdot \sum _{x'',y''} I(x+x'',y+y'') \end{array}\]

  6. method=TM_CCOEFF_NORMED

    \[R(x,y)= \frac{ \sum_{x',y'} (T'(x',y') \cdot I'(x+x',y+y')) }{ \sqrt{\sum_{x',y'}T'(x',y')^2 \cdot \sum_{x',y'} I'(x+x',y+y')^2} }\]

コード

  • What does this program do?
    • 入力画像、画像パッチ(テンプレート)、および省略可能でマスクを読み込む
    • 前述の6つのマッチング手法のいずれかを使い、OpenCVの関数 matchTemplate() でテンプレートマッチング処理を実行する。ユーザーはトラックバーで選択を入力して手法を選べる。マスクが与えられた場合、マスクをサポートする手法でのみ使用される
    • マッチング処理の出力を正規化する
    • マッチング確率が高い位置を特定する
    • 最も高いマッチに対応する領域の周囲に矩形を描画する

解説

  • 画像、テンプレート、結果の行列、ならびにマッチング手法とウィンドウ名など、いくつかのグローバル変数を宣言する:

  • 元画像、テンプレート、および省略可能でマッチング手法がサポートする場合はマスクを読み込む:

  • 使用するマッチング手法の種類を入力するためのトラックバーを作成する。変更が検出されるとコールバック関数が呼び出される。

  • コールバック関数を見てみよう。まず、元画像のコピーを作成する:

  • テンプレートマッチング処理を実行する。引数は当然ながら入力画像 I、テンプレート T、結果 R、match_method(トラックバーで指定)、および省略可能でマスク画像 M である。

  • 結果を正規化する:

  • minMaxLoc() を使って結果行列 R の最小値と最大値を特定する。

  • 最初の2つの手法( TM_SQDIFF と MT_SQDIFF_NORMED )では、最良のマッチは最小値である。それ以外のすべての手法では、値が大きいほどよいマッチを表す。そこで、対応する値を matchLoc 変数に保存する:

  • 元画像と結果行列を表示する。最も高いマッチの可能性がある領域の周囲に矩形を描画する:

結果

  1. 次のような入力画像でプログラムをテストする:

およびテンプレート画像:

  1. 以下の結果行列が生成される(1行目は標準的な手法 SQDIFF、CCORR、CCOEFF、2行目はそれらの正規化版である)。1列目では最も暗い箇所がよいマッチで、他の2列では位置が明るいほどマッチが高い。

  1. 正しいマッチを以下に示す(右側の男性の顔の周囲の黒い矩形)。CCORR と CCDEFF は誤った最良マッチを与えたが、それらの正規化版は正しく検出したことに注意してほしい。これは、「最も高いマッチ」だけを考慮し、他の可能性のある高いマッチを考慮していないことが原因かもしれない。