当前位置: 首页 > news >正文

opencv 模板匹配方法汇总

在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,表示匹配程度越高。
  • 特点:对光照变化具有较强的鲁棒性,是一种比较稳定的匹配方法。
  • 适用场景:在各种光照条件下都能有较好的表现,是最常用的模板匹配方法之一。

代码示例

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()

这个示例代码展示了如何使用不同的模板匹配方法在图像中查找模板的位置,并在图像上绘制矩形框标记匹配结果。你可以根据实际需求选择合适的匹配方法。

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

相关文章:

  • c语言笔记 数组篇
  • vue videojs使用canvas截取视频画面
  • Linux命令常用的有哪些?
  • nlp第十节——LLM相关
  • 013-2 订单支付超时自动取消订单(rocketmq jpa)
  • 迷你世界脚本玩家接口:Player
  • 蓝桥杯2025模拟三(01字符串)
  • Python Tornado 框架面试题及参考答案
  • 【leetcode hot 100 76】最小覆盖子串
  • TypeScript系列01-类型系统全解析
  • 【中值滤波器(Median Filter)详解】
  • go routine 并发和同步
  • 虚拟机的IP配置
  • 网络安全月度报告
  • LLM 对话框组件 | 字节青训营前端开发项目
  • 计算机网络-实验四子网划分
  • 拒绝被假量薅羊毛,游戏渠道反作弊解决方案发布
  • go类型转换
  • Docker 模拟 kubernetes 的 pod
  • 【C++】:STL详解 —— priority_queue类
  • 做二维码推送网站/整站优化快速排名
  • 网站解析后怎么解决方法/app投放推广
  • 做网站最小的字体是多少钱/官网seo优化找哪家做
  • 晋中做网站的公司/网络营销第三版课本
  • 微信公众号 手机网站开发/软文推广的标准类型
  • wordpress4.7.1/seo教程seo教程