Cv2.MatchTemplate の使い方【OpenCV/C#(OpenCvSharp)】〜テンプレートマッチングで部分画像を検索する〜

OpenCV for C#
📌 準備: OpenCV の環境構築がまだの方はこちら → C++ 環境構築ガイド / C#(OpenCvSharp)セットアップ

Cv2.MatchTemplate は、画像内から指定したテンプレート画像と一致する領域を探す関数です。工場の外観検査・UIテストの座標特定・画面上のアイコン検索など、実務でよく使われます。最小限のコードはこうなります。

Cv2.MatchTemplate(src, templ, result, TemplateMatchModes.CCoeffNormed);
Cv2.MinMaxLoc(result, out _, out double maxVal, out _, out Point maxLoc);

動作環境

項目 バージョン
OpenCV 4.x 系
OpenCvSharp4 4.x 系(NuGet)
.NET 8(コンソール)
OS Windows

NuGet パッケージ: OpenCvSharp4 と OpenCvSharp4.runtime.win の両方が必要です。

環境構築がまだの方は環境構築ガイドを先にどうぞ。


基本の使い方

次のサンプルは、画像 src.png の中からテンプレート templ.png と最もよく一致する箇所を探し、その位置に矩形を描画して保存します。

using OpenCvSharp;

// 元画像とテンプレート画像を読み込む
using var src    = Cv2.ImRead("src.png",   ImreadModes.Color);
using var templ  = Cv2.ImRead("templ.png", ImreadModes.Color);

if (src.Empty() || templ.Empty())
{
    Console.WriteLine("画像の読み込みに失敗しました。");
    return;
}

// マッチング結果を格納する Mat(サイズは自動計算される)
using var result = new Mat();

// テンプレートマッチング実行(正規化相互相関係数)
Cv2.MatchTemplate(src, templ, result, TemplateMatchModes.CCoeffNormed);

// 最大スコアの位置を取得(CCoeffNormed は値が大きいほど一致)
Cv2.MinMaxLoc(result, out _, out double maxVal, out _, out Point maxLoc);

Console.WriteLine($"最大スコア: {maxVal:F4}  位置: {maxLoc}");

// 検出位置に矩形を描画
var matchRect = new Rect(maxLoc.X, maxLoc.Y, templ.Width, templ.Height);
Cv2.Rectangle(src, matchRect, Scalar.Red, 2);

Cv2.ImWrite("result.png", src);
Console.WriteLine("result.png を保存しました。");

実行結果の例(コンソール出力)

最大スコア: 0.9987  位置: (142, 88)
result.png を保存しました。

行ごとの解説

行 内容
Cv2.MatchTemplate(...) 元画像とテンプレートを比較し、各位置のスコアを result に書き出す
TemplateMatchModes.CCoeffNormed 正規化相互相関係数。−1〜1 の範囲で 1 が完全一致
Cv2.MinMaxLoc(...) スコアマップ中の最大値と、その座標を取得する
new Rect(maxLoc.X, maxLoc.Y, ...) テンプレートと同サイズの矩形を一致位置に配置

引数と戻り値

Cv2.MatchTemplate(Mat image, Mat templ, Mat result, TemplateMatchModes method, Mat? mask = null)
引数 型 説明
image Mat 検索対象の元画像(8U または 32F)
templ Mat テンプレート画像。image より小さい必要がある
result Mat 出力スコアマップ。サイズは (W - w + 1) × (H - h + 1)
method TemplateMatchModes マッチング手法(下表)
mask Mat? テンプレートのマスク(省略可。TM_SQDIFF / TM_CCORR_NORMED のみ有効)

主な TemplateMatchModes

値 特徴
SqDiff 差分二乗和。最小値が最良一致
SqDiffNormed 正規化版。最小値が最良一致
CCorr 相互相関。最大値が最良一致
CCorrNormed 正規化版。最大値が最良一致
CCoeff 相互相関係数。最大値が最良一致
CCoeffNormed 正規化版。最大値が最良一致 ✅ 実務で最もよく使う

実践例

例1: 閾値でマッチングの成否を判定する

スコアが閾値を超えない場合は「見つからなかった」と扱うパターンです。工場の部品検査で定番の実装です。

using OpenCvSharp;

using var src   = Cv2.ImRead("src.png",   ImreadModes.Color);
using var templ = Cv2.ImRead("templ.png", ImreadModes.Color);
using var result = new Mat();

Cv2.MatchTemplate(src, templ, result, TemplateMatchModes.CCoeffNormed);
Cv2.MinMaxLoc(result, out _, out double maxVal, out _, out Point maxLoc);

const double threshold = 0.85;

if (maxVal >= threshold)
{
    Console.WriteLine($"検出成功: スコア={maxVal:F4}  位置={maxLoc}");
    var rect = new Rect(maxLoc.X, maxLoc.Y, templ.Width, templ.Height);
    Cv2.Rectangle(src, rect, Scalar.LimeGreen, 2);
    Cv2.ImWrite("found.png", src);
}
else
{
    Console.WriteLine($"検出失敗: スコア={maxVal:F4}(閾値 {threshold} 未満)");
}
検出成功: スコア=0.9912  位置=(204, 56)

例2: 複数箇所を同時に検出する

同じ部品が複数並んでいる画像など、すべての一致箇所を取り出したいときは、スコアマップを走査します。

using OpenCvSharp;

using var src    = Cv2.ImRead("src.png",   ImreadModes.Color);
using var templ  = Cv2.ImRead("templ.png", ImreadModes.Color);
using var result = new Mat();

Cv2.MatchTemplate(src, templ, result, TemplateMatchModes.CCoeffNormed);

// 閾値以上のピクセルをマスクとして取得
using var mask = new Mat();
Cv2.Threshold(result, mask, 0.85, 1.0, ThresholdTypes.Tozero);

int count = 0;
while (true)
{
    // 残っている最大値を取得
    Cv2.MinMaxLoc(mask, out _, out double maxVal, out _, out Point maxLoc);
    if (maxVal < 0.85) break;

    count++;
    var rect = new Rect(maxLoc.X, maxLoc.Y, templ.Width, templ.Height);
    Cv2.Rectangle(src, rect, Scalar.Red, 2);

    // 検出済み領域をマスクして次のピークを探す
    // テンプレートサイズ分を 0 に塗りつぶして重複を防ぐ
    var maskRoi = new Mat(mask, rect);
    maskRoi.SetTo(0);
}

Console.WriteLine($"{count} 箇所を検出しました。");
Cv2.ImWrite("multi_result.png", src);
3 箇所を検出しました。

⚠️ 重複排除のロジックはテンプレートサイズに依存します。必要に応じて Non-Maximum Suppression を実装してください。


つまずきポイント

① result Mat のサイズに注意

result のサイズは元画像のサイズではなく (W - w + 1) × (H - h + 1) になります。maxLoc はこのスコアマップ上の座標なので、そのまま元画像の矩形描画に使えます(ずれはしない)。ただし result を別の目的に使うときはサイズを確認してください。

② SqDiff 系は最小値が一致箇所

CCoeffNormed や CCorrNormed は最大値が一致箇所ですが、SqDiff / SqDiffNormed は最小値が一致箇所です。MinMaxLoc で取得する座標を maxLoc ではなく minLoc に切り替える必要があります。間違えると全く엉뚱한位置に矩形が描かれます。

// SqDiff 系を使う場合
Cv2.MinMaxLoc(result, out double minVal, out _, out Point minLoc, out _);
// → minLoc を使う

③ テンプレートが元画像より大きいと例外が出る

templ のサイズが image のサイズ以上だと OpenCV 内部でエラーになります。マッチング前に templ.Width < src.Width && templ.Height < src.Height を確認するガードを入れておくと安全です。


関連する関数


まとめ

Cv2.MatchTemplate + Cv2.MinMaxLoc の組み合わせで、画像内の部分一致位置を数行で取得できます。手法は CCoeffNormed を基本に選び、スコアの閾値で成否を判定するのが実務での定番パターンです。複数検出が必要な場合は、検出済み領域をマスクしてループする方法が手軽に実装できます。

🛠 画像処理のプロが開発するSDK/API

本ブログを運営するスワローインキュベートは、OpenCV ベースのなりすまし判定SDK/APIを開発しています。SDK は C#/.NET 8 に正式対応しており、OpenCvSharp を使うプロジェクトからそのまま組み込めます。

→ 顔認証のなりすまし対策 設計チェックリスト(当ブログ)
→ なりすまし判定SDK/APIの詳細を見る
→ API仕様書・サンプルコード

タイトルとURLをコピーしました