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.MinMaxLoc —
MatchTemplateの結果から最良一致座標を取り出すために必須。セットで覚えてください - Cv2.Normalize — スコアマップを 0〜255 に正規化して可視化したいときに使います
- Cv2.Canny の使い方【OpenCV/C#(OpenCvSharp)】〜エッジ検出で輪郭を抽出する〜 — テンプレートをエッジ画像に変換してからマッチングすると照明変動に強くなります
- Cv2.MorphologyEx の使い方【OpenCV/C#(OpenCvSharp)】〜モルフォロジー変換でノイズ除去・穴埋めを行う〜 — 検出後の後処理でバイナリマスクを整形するときに役立ちます
まとめ
Cv2.MatchTemplate + Cv2.MinMaxLoc の組み合わせで、画像内の部分一致位置を数行で取得できます。手法は CCoeffNormed を基本に選び、スコアの閾値で成否を判定するのが実務での定番パターンです。複数検出が必要な場合は、検出済み領域をマスクしてループする方法が手軽に実装できます。
🛠 画像処理のプロが開発するSDK/API
本ブログを運営するスワローインキュベートは、OpenCV ベースのなりすまし判定SDK/APIを開発しています。SDK は C#/.NET 8 に正式対応しており、OpenCvSharp を使うプロジェクトからそのまま組み込めます。
→ 顔認証のなりすまし対策 設計チェックリスト(当ブログ)
→ なりすまし判定SDK/APIの詳細を見る
→ API仕様書・サンプルコード
