基于 OpenCV 的模板匹配算法的 C 语言实现

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;
}

编译与运行

bash 复制代码
# 编译(需安装OpenCV开发库)
gcc template_matching.c -o tm `pkg-config --cflags --libs opencv`

# 运行
./tm

关键函数说明

  1. cvMatchTemplate() - 核心匹配函数

    c 复制代码
    void cvMatchTemplate(
        const CvArr* image,      // 目标图像
        const CvArr* templ,      // 模板图像
        CvArr* result,           // 结果矩阵
        int method               // 匹配方法
    );

    支持的匹配方法:

    • CV_TM_SQDIFF:平方差匹配法
    • CV_TM_CCORR:相关匹配法
    • CV_TM_CCOEFF:相关系数匹配法
    • 加上_NORMED后缀表示归一化版本(推荐)
  2. cvMinMaxLoc() - 查找极值位置

    c 复制代码
    void cvMinMaxLoc(
        const CvArr* arr,        // 输入数组
        double* min_val,          // 最小值指针
        double* max_val,          // 最大值指针
        CvPoint* min_loc,         // 最小值位置
        CvPoint* max_loc,         // 最大值位置
        const CvArr* mask = NULL  // 可选掩码
    );

多目标匹配增强版

c 复制代码
// 在找到最大值后添加多目标处理:
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);

参考代码 基于opencv的模板匹配算法,可以从一副大图中搜索出与模板相似度最高的部分 youwenfan.com/contentcso/72869.html

算法特点及注意事项

  1. 适用场景:

    • 固定大小的物体检测
    • 不变形、不旋转的模板
    • 光照变化较小的环境
  2. 性能优化:

    c 复制代码
    // 转换为灰度图提高速度
    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);
    // 然后使用灰度图进行匹配
  3. 常见问题解决:

    • 旋转问题:旋转模板创建多个版本
    • 尺度问题:使用图像金字塔多尺度匹配
    • 光照问题:使用边缘特征(Canny)代替原始图像
  4. 替代方案建议:

    • 当模板>图像尺寸25%时,考虑特征匹配(SIFT/SURF)
    • 复杂场景下使用YOLO等深度学习模型

此实现使用OpenCV的C接口,兼容OpenCV 2.x版本。对于新项目,推荐使用OpenCV C++ API(Mat类代替IplImage)。

相关推荐
GreatSQL社区9 分钟前
主从复制SQL线程中断——字符集砸出的坑
java·数据库·算法
Tisfy1 小时前
LeetCode 2333.最小差值平方和:排序 + 数学计算(不用二分)
数学·算法·leetcode·题解·贪心·排序
aqiu1111111 小时前
【C++算法打怪专栏】LeetCode 217. 存在重复元素(解法总结)
c++·算法·leetcode
iotxiaohu2 小时前
用 cflow 查看 C 函数调用关系
c语言·开发语言·cflow
yi0113 小时前
DAY28: LeetCode 111. 二叉树的最小深度
人工智能·笔记·python·算法·leetcode·二叉树·递归
wuyk5553 小时前
27.LeetCode 2265. 统计值等于子树平均值的节点数 —— 后序遍历实战
stm32·单片机·嵌入式硬件·算法
xiangyun613 小时前
C++ list 模拟实现(二):const迭代器与反向迭代器,模板的黑魔法
开发语言·数据库·c++·算法·stl·list
xxwl5853 小时前
三、区域赛算法模版第三章---字符串相关算法
笔记·学习·算法
信奥卷王3 小时前
[GESP202509 六级] 划分字符串(含视频)
数据结构·算法
酒醉的胡铁4 小时前
相似度搜索的常见算法
算法·ai