opencv 寻找匹配物体
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

更多推荐



所有评论(0)