基于 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

关键函数说明

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

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

    支持的匹配方法:

    • CV_TM_SQDIFF:平方差匹配法
    • CV_TM_CCORR:相关匹配法
    • CV_TM_CCOEFF:相关系数匹配法
    • 加上_NORMED后缀表示归一化版本(推荐)
  2. 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);

算法特点及注意事项

  1. 适用场景

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

    // 转换为灰度图提高速度
    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)。

posted @ 2025-07-27 16:06  荒川之主  阅读(27)  评论(0)    收藏  举报