在OpenCV中,模板匹配是一种在较大图像中查找特定模板图像位置的技术。OpenCV提供了多种模板匹配方法,通过cv2.matchTemplate
函数实现,该函数支持的匹配方式主要有以下6种,下面详细介绍每种方法的原理、特点和适用场景。
1. cv2.TM_SQDIFF
(平方差匹配法)
- 原理:计算模板与图像中每个可能位置的像素值平方差的总和。匹配结果值越小,表示匹配程度越高。
- 特点:对光照变化比较敏感,因为它直接比较像素值的差异。
- 公式 : R ( x , y ) = ∑ x ′ , y ′ ( T ( x ′ , y ′ ) − I ( x + x ′ , y + y ′ ) ) 2 R(x,y)=\sum _{x',y'} (T(x',y') - I(x + x',y + y'))^2 R(x,y)=∑x′,y′(T(x′,y′)−I(x+x′,y+y′))2,其中 T T T 是模板图像, I I I 是输入图像, R R R 是匹配结果图像。
- 适用场景:适用于模板和目标图像的光照条件较为一致的情况。
2. cv2.TM_SQDIFF_NORMED
(归一化平方差匹配法)
- 原理 :是
cv2.TM_SQDIFF
的归一化版本,将平方差结果归一化到 [0, 1] 范围内。匹配结果值越接近 0,表示匹配程度越高。 - 特点:对光照变化有一定的鲁棒性,因为归一化操作减少了不同图像之间像素值范围差异的影响。
- 适用场景:当模板和目标图像的光照有一定差异,但差异不是特别大时适用。
3. cv2.TM_CCORR
(相关性匹配法)
- 原理:计算模板与图像中每个可能位置的像素值相关性。匹配结果值越大,表示匹配程度越高。
- 特点:对光照变化也比较敏感,因为它直接依赖于像素值的相关性。
- 公式 : R ( x , y ) = ∑ x ′ , y ′ ( T ( x ′ , y ′ ) ⋅ I ( x + x ′ , y + y ′ ) ) R(x,y)=\sum _{x',y'} (T(x',y') \cdot I(x + x',y + y')) R(x,y)=∑x′,y′(T(x′,y′)⋅I(x+x′,y+y′))
- 适用场景:适用于模板和目标图像的光照条件较为一致,且模板和目标之间的亮度模式相似的情况。
4. cv2.TM_CCORR_NORMED
(归一化相关性匹配法)
- 原理 :是
cv2.TM_CCORR
的归一化版本,将相关性结果归一化到 [0, 1] 范围内。匹配结果值越接近 1,表示匹配程度越高。 - 特点:对光照变化有较好的鲁棒性,因为归一化操作消除了不同图像之间像素值范围差异的影响。
- 适用场景:在光照条件不稳定的情况下,是一种比较常用的匹配方法。
5. cv2.TM_CCOEFF
(相关系数匹配法)
- 原理:计算模板与图像中每个可能位置的像素值相关系数。匹配结果值越大,表示匹配程度越高。相关系数衡量的是两个信号之间的线性相关性。
- 特点:对光照变化有一定的鲁棒性,因为它考虑了模板和图像的均值。
- 适用场景:适用于模板和目标图像的光照有一定差异,但整体结构相似的情况。
6. cv2.TM_CCOEFF_NORMED
(归一化相关系数匹配法)
- 原理 :是
cv2.TM_CCOEFF
的归一化版本,将相关系数结果归一化到 [-1, 1] 范围内。匹配结果值越接近 1,表示匹配程度越高。 - 特点:对光照变化具有较强的鲁棒性,是一种比较稳定的匹配方法。
- 适用场景:在各种光照条件下都能有较好的表现,是最常用的模板匹配方法之一。
代码示例
python
import cv2
import numpy as np
# 读取图像和模板
img = cv2.imread('image.jpg', 0)
template = cv2.imread('template.jpg', 0)
h, w = template.shape[:2]
# 定义匹配方法
methods = ['cv2.TM_SQDIFF', 'cv2.TM_SQDIFF_NORMED', 'cv2.TM_CCORR',
'cv2.TM_CCORR_NORMED', 'cv2.TM_CCOEFF', 'cv2.TM_CCOEFF_NORMED']
for meth in methods:
img2 = img.copy()
method = eval(meth)
# 执行模板匹配
res = cv2.matchTemplate(img2, template, method)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
# 根据不同的匹配方法确定最佳匹配位置
if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]:
top_left = min_loc
else:
top_left = max_loc
bottom_right = (top_left[0] + w, top_left[1] + h)
# 在图像上绘制矩形框标记匹配位置
cv2.rectangle(img2, top_left, bottom_right, 255, 2)
# 显示结果
cv2.imshow(meth, img2)
cv2.waitKey(0)
cv2.destroyAllWindows()
这个示例代码展示了如何使用不同的模板匹配方法在图像中查找模板的位置,并在图像上绘制矩形框标记匹配结果。你可以根据实际需求选择合适的匹配方法。
cpp
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
// 定义模板匹配方法名称和对应的枚举值
const char* method_names[] = { "TM_SQDIFF", "TM_SQDIFF_NORMED", "TM_CCORR",
"TM_CCORR_NORMED", "TM_CCOEFF", "TM_CCOEFF_NORMED" };
const int methods[] = { TM_SQDIFF, TM_SQDIFF_NORMED, TM_CCORR,
TM_CCORR_NORMED, TM_CCOEFF, TM_CCOEFF_NORMED };
int main()
{
// 读取图像和模板
Mat img = imread("image.jpg", IMREAD_GRAYSCALE);
Mat template_img = imread("template.jpg", IMREAD_GRAYSCALE);
if (img.empty() || template_img.empty())
{
cout << "Could not open or find the image or template" << endl;
return -1;
}
int h = template_img.rows;
int w = template_img.cols;
// 遍历不同的匹配方法
for (int i = 0; i < 6; i++)
{
Mat img2 = img.clone();
Mat result;
// 执行模板匹配
matchTemplate(img2, template_img, result, methods[i]);
double minVal, maxVal;
Point minLoc, maxLoc;
// 查找匹配结果中的最小值和最大值以及它们的位置
minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc);
Point topLeft;
bool isMatch = false;
// 根据不同的匹配方法确定最佳匹配位置,并判断是否匹配成功
if (methods[i] == TM_SQDIFF || methods[i] == TM_SQDIFF_NORMED)
{
topLeft = minLoc;
if (methods[i] == TM_SQDIFF_NORMED && minVal < 0.1) // 可调整阈值
{
isMatch = true;
}
}
else if (methods[i] == TM_CCORR_NORMED && maxVal > 0.8) // 可调整阈值
{
topLeft = maxLoc;
isMatch = true;
}
else if (methods[i] == TM_CCOEFF_NORMED && maxVal > 0.8) // 可调整阈值
{
topLeft = maxLoc;
isMatch = true;
}
if (isMatch)
{
Point bottomRight(topLeft.x + w, topLeft.y + h);
// 在图像上绘制矩形框标记匹配位置
rectangle(img2, topLeft, bottomRight, Scalar(255), 2);
}
else
{
cout << "No match found using " << method_names[i] << endl;
}
// 显示结果
imshow(method_names[i], img2);
}
waitKey(0);
destroyAllWindows();
return 0;
}