1. Mat 

 create

// 方式1:行数、列数、类型
void Mat::create(int rows, int cols, int type);

// 方式2:Size(width, height),注意Size是(宽,高) = (cols, rows)
void Mat::create(Size sz, int type);

// 方式3:多维矩阵
void Mat::create(int ndims, const int* sizes, int type);

方法一:

Mat imgRes;
int row = 2;
int column = 2;
imgRes.create(row,column, CV_32FC1);

copyTo

Mat imgSrc = imread(imgPath.toStdString());
Mat imgDst;
imgSrc.copyTo(imgDst);

2. 模板匹配

void cv::matchTemplate(

        InputArray image, // 源图像,待搜索大图

        InputArray templ, // 模板小图,要找的目标

        OutputArray result, // 输出结果矩阵

        int method, // 匹配算法

        InputArray mask = noArray() // 掩码(可选)

);

重要尺寸规则

  • 假设原图:H × W,模板:h × w
  • 输出 result 矩阵大小:(H‑h+1) × (W‑w+1)
  • result 中每一个像素代表:模板放在该位置时的匹配分数

result  分数矩阵

模版小图在大图上滑动窗口,窗口左上角坐标(x,y)

对每滑到一个(x,y)位置,就计算一次匹配分数,存到result(y,x)

TM_CCOEFF_NORMED 最常用

QString imgSrcPath = "XXXX";
Mat imgSrc = imread(imgSrcPath .toStdString());
cvtColor(imgdata, imgdata, COLOR_BGR2RGB);

QString imgTmpPAth = "xxxxx";
Mat imgTmp = imread(imgTmpPAth .toStdString());
cvtColor(imgTmp , imgTmp , COLOR_BGR2RGB);

int rows = imgSrc.rows - imgTmp.rows;
int columns = imgSrc.cols - imgTmp.cols;
Mat imgRes(rows, columns, CV_32FC1);

matchTemplate(imgSrc, imgTmp, imgRes, TM_CCOEFF_NOREAM);

3. 标准化 分数缩放(把分数从原来值域换到另一个值域)

void cv::normalize(

         InputArray src, // 输入矩阵,可以是1D/2D,单通道多通道

        OutputArray dst, // 输出矩阵,和src同尺寸同类型

        double alpha = 1, // 归一化后最小值/最大值,看normType

        double beta = 0, // 归一化后另一个边界

        int normType = NORM_L2,// 归一化模式

        int dtype = -1, // -1:dst和src类型一致;指定类型如CV_8U

        InputArray mask = noArray() // 掩码,只处理mask非0像素

);

NORM_MINMAX 【最常用】线性缩放到 [alpha, beta]

normalize(imgRes, imgRes, 0, 1, NORM_MINMAX);

4. 获取分数矩阵中的 最小值 最大值 及其 坐标

void cv::minMaxLoc(

        InputArray src, // 输入:单通道矩阵 (常用 matchTemplate 的 result,CV_32FC1)         double* minVal, // 输出:矩阵内最小数值

        double* maxVal = 0, // 输出:矩阵内最大数值

        Point* minLoc = 0, // 输出:最小值坐标

        Point(x,y) Point* maxLoc = 0, // 输出:最大值坐标

        Point(x,y) InputArray mask = noArray() // 掩码,只在mask非0区域查找

);

double minValue;
double maxValue;
Point minPoint;
Point maxPoint;
Point matchPoint;

minMaxLoc(imgRes, &minValue, &maxValue, &minPoint, &maxPoint, Mat());

5. opencv 绘制矩形

// 版本1:传入左上角、右下角

Point void cv::rectangle(

        InputOutputArray img, // 要绘制的图像,直接修改原图

        Point pt1, // 左上角点 Point pt2, // 右下角点

        const Scalar& color, // BGR颜色 Scalar(B,G,R)

        int thickness = 1, // 线宽;-1 = 填充矩形

        int lineType = LINE_8, // 线型 int shift = 0

);

// 版本2:传入 Rect 对象

void cv::rectangle(

        InputOutputArray img,

        Rect rec, // Rect(x,y,width,height)

        const Scalar& color,

        int thickness = 1,

        int lineType = LINE_8,

        int shift = 0

);

//版本一
rectangle(
    imgSrc,
    matchPoint,
    Point(matchPoint.x + imgTmp.cols, matchPoint.y + imgTmp.rows),
    Scalar(238,238,0),
    4,
    8,
    0    
);

// 在imgSrc 上 框出 匹配得分最高的区域 matchPoint(左上角)

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <opencv2/opencv.hpp>

QT_BEGIN_NAMESPACE
using namespace cv;
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

    void initmainwindow();
    void imgShow();
    void imgProc();

private slots:
    void on_pushButton_clicked();

private:
    Ui::MainWindow *ui;

    Mat myImg;
    QImage myQImg;
};
#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    initmainwindow();
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::initmainwindow()
{
    QString imgPath = R"(D:\new_share\016_opencv\OpencvBlend\5.webp)";
    Mat imgData = imread(imgPath.toStdString());
    cvtColor(imgData, imgData, COLOR_BGR2RGB);
    myImg = imgData;

    myQImg = QImage((const unsigned char*)imgData.data, imgData.cols, imgData.rows, static_cast<int>(imgData.step), QImage::Format_RGB888);
    imgShow();
}

void MainWindow::imgShow()
{
    ui->label->setPixmap(QPixmap::fromImage(myQImg));
}

void MainWindow::imgProc()
{
    // 处理待匹配子图
    QString imgPath = R"(D:\new_share\016_opencv\OpencvBlend\5.png)";
    Mat imgTmp = imread(imgPath.toStdString());
    cvtColor(imgTmp, imgTmp, COLOR_BGR2RGB);

    // 设置的得分矩阵
    Mat imgRes;
    Mat imgSrc = myImg;
    int rescols = imgSrc.cols - imgTmp.cols;
    int resrows = imgSrc.rows - imgTmp.rows;
    imgRes.create(resrows, rescols, CV_32FC1);

    // 进行匹配
    int METHOD = TM_CCOEFF_NORMED;   // 标准相关匹配
    matchTemplate(imgSrc, imgTmp, imgRes, METHOD);

    // 标准化 分数缩放
    normalize(imgRes, imgRes, 0, 1, NORM_MINMAX);

    // 获取得分 最小 最大 及其 坐标
    double minValue;
    double maxValue;
    Point minPoint;
    Point maxPoint;
    Point matchPoint;
    minMaxLoc(imgRes, &minValue, &maxValue, &minPoint, &maxPoint, Mat());

    // 方差匹配 或者 标准方差匹配 得分越小相似度越大        其他匹配方法得分越大,相似度越大
    if(METHOD == TM_SQDIFF || METHOD == TM_SQDIFF_NORMED)
        matchPoint = minPoint;
    else
        matchPoint = maxPoint;

    // 框选
    Mat imgDisplay;
    imgSrc.copyTo(imgDisplay);
    rectangle(imgDisplay, matchPoint, Point(matchPoint.x + imgTmp.cols, matchPoint.y + imgTmp.rows), Scalar(238, 238,0), 4, 8 ,0);
    rectangle(imgRes, matchPoint, Point(matchPoint.x + imgTmp.cols, matchPoint.y + imgTmp.rows), Scalar::all(0), 2, 8, 0);   //  调试

    myQImg = QImage((const unsigned char *)imgDisplay.data, imgDisplay.cols, imgDisplay.rows, static_cast<int>(imgDisplay.step), QImage::Format_RGB888);
    imgShow();
}

void MainWindow::on_pushButton_clicked()
{
    imgProc();
}

mainwindow.ui

更多推荐