基于 OpenCV 的模板匹配算法的 C 语言实现
基于 OpenCV 的模板匹配算法的 C 语言实现
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui_c.h>
#include <stdio.h>
int main() {
// 1. 读取目标图像和模板图像
IplImage* target = cvLoadImage("target.jpg", CV_LOAD_IMAGE_COLOR);
IplImage* template_img = cvLoadImage("template.jpg", CV_LOAD_IMAGE_COLOR);
if(!target || !template_img) {
printf("错误:无法加载图像!\n");
return -1;
}
// 2. 获取模板尺寸
int width = template_img->width;
int height = template_img->height;
// 3. 创建匹配结果矩阵
CvSize result_size;
result_size.width = target->width - width + 1;
result_size.height = target->height - height + 1;
IplImage* result = cvCreateImage(result_size, IPL_DEPTH_32F, 1);
// 4. 执行模板匹配(使用归一化相关系数法)
cvMatchTemplate(target, template_img, result, CV_TM_CCOEFF_NORMED);
// 5. 寻找最佳匹配位置
double min_val, max_val;
CvPoint min_loc, max_loc;
cvMinMaxLoc(result, &min_val, &max_val, &min_loc, &max_loc, NULL);
printf("最高相似度: %.2f\n", max_val);
// 6. 设置匹配阈值(0-1之间)
double threshold = 0.8;
if(max_val >= threshold) {
// 7. 绘制匹配矩形(绿色)
cvRectangle(
target,
max_loc,
cvPoint(max_loc.x + width, max_loc.y + height),
CV_RGB(0, 255, 0),
2
);
printf("匹配位置: (%d, %d)\n", max_loc.x, max_loc.y);
} else {
printf("未找到匹配项!\n");
}
// 8. 显示结果
cvNamedWindow("目标图像", CV_WINDOW_AUTOSIZE);
cvShowImage("目标图像", target);
cvNamedWindow("模板图像", CV_WINDOW_AUTOSIZE);
cvShowImage("模板图像", template_img);
// 9. 等待按键
cvWaitKey(0);
// 10. 清理资源
cvReleaseImage(&target);
cvReleaseImage(&template_img);
cvReleaseImage(&result);
cvDestroyAllWindows();
return 0;
}
编译与运行
# 编译(需安装OpenCV开发库)
gcc template_matching.c -o tm `pkg-config --cflags --libs opencv`
# 运行
./tm
关键函数说明
-
cvMatchTemplate()- 核心匹配函数void cvMatchTemplate( const CvArr* image, // 目标图像 const CvArr* templ, // 模板图像 CvArr* result, // 结果矩阵 int method // 匹配方法 );支持的匹配方法:
CV_TM_SQDIFF:平方差匹配法CV_TM_CCORR:相关匹配法CV_TM_CCOEFF:相关系数匹配法- 加上
_NORMED后缀表示归一化版本(推荐)
-
cvMinMaxLoc()- 查找极值位置void cvMinMaxLoc( const CvArr* arr, // 输入数组 double* min_val, // 最小值指针 double* max_val, // 最大值指针 CvPoint* min_loc, // 最小值位置 CvPoint* max_loc, // 最大值位置 const CvArr* mask = NULL // 可选掩码 );
参考代码 基于opencv的模板匹配算法,可以从一副大图中搜索出与模板相似度最高的部分 youwenfan.com/contentcna/72869.html
多目标匹配增强版
// 在找到最大值后添加多目标处理:
CvPoint* locations = NULL;
int match_count = 0;
double threshold = 0.75;
// 获取所有高于阈值的匹配位置
for(int y = 0; y < result->height; y++) {
float* row = (float*)(result->imageData + y * result->widthStep);
for(int x = 0; x < result->width; x++) {
if(row[x] >= threshold) {
match_count++;
locations = (CvPoint*)realloc(locations, match_count * sizeof(CvPoint));
locations[match_count-1] = cvPoint(x, y);
}
}
}
// 绘制所有匹配位置
for(int i = 0; i < match_count; i++) {
cvRectangle(
target,
locations[i],
cvPoint(locations[i].x + width, locations[i].y + height),
CV_RGB(0, 255, 0),
2
);
}
free(locations);
算法特点及注意事项
-
适用场景:
- 固定大小的物体检测
- 不变形、不旋转的模板
- 光照变化较小的环境
-
性能优化:
// 转换为灰度图提高速度 IplImage* gray_target = cvCreateImage(cvGetSize(target), IPL_DEPTH_8U, 1); IplImage* gray_template = cvCreateImage(cvGetSize(template_img), IPL_DEPTH_8U, 1); cvCvtColor(target, gray_target, CV_BGR2GRAY); cvCvtColor(template_img, gray_template, CV_BGR2GRAY); // 然后使用灰度图进行匹配 -
常见问题解决:
- 旋转问题:旋转模板创建多个版本
- 尺度问题:使用图像金字塔多尺度匹配
- 光照问题:使用边缘特征(Canny)代替原始图像
-
替代方案建议:
- 当模板>图像尺寸25%时,考虑特征匹配(SIFT/SURF)
- 复杂场景下使用YOLO等深度学习模型
此实现使用OpenCV的C接口,兼容OpenCV 2.x版本。对于新项目,推荐使用OpenCV C++ API(Mat类代替IplImage)。

浙公网安备 33010602011771号