除基本的图片处理功能外,OpenCV还是一个强大的计算机视觉库,基于各种人工智能算法及计算机视觉技术的最新成就,可以做到精准地识别、定位出画面中特定的物体和人脸各器官的位置。
寻找匹配物体实例。现有一张美人鱼公主动漫图片(见下面左图),我们想让计算机从这张图片中找出一条小鱼(见下面右图),并标示出它的位置。
1.程序界面
创建一个Qt桌面应用程序项目,项目名称为“OpencvObjMatch”,设计程序界面如图所示。
2.全局变量及方法
为了提高程序代码的使用效率,通常建议将程序中公用的图片对象的句柄声明为全局变量,通用的方法声明为公有(public)方法,定义在项目.h头文件中。
“mainwindow.h”头文件,代码如下:
#include <QMainWindow>
#include "opencv2/opencv.hpp" //OpenCV文件包含
using namespace cv; //OpenCV 命名空间
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
void initMainWindow(); //界面初始化
void imgProc(); // 处理图片
void imgShow(); // 显示图片
private slots:
void on_btnMatch_clicked();//“开始匹配”按钮单击事件槽
private:
Ui::MainWindow *ui;
Mat myImg;//缓存图片(供程序代码引用和处理)
QImage myQImg;//保存图片(可转为文件存盘或显示)
};
3.初始化显示
首先在Qt界面上显示要从中匹配物体的图片,在构造方法中添加如下代码:
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent), ui(new Ui::MainWindow)
{
ui->setupUi(this);
initMainWindow();
}
初始化方法initMainWindow()的代码为:
void MainWindow::initMainWindow()
{
QString imgPath = "mermaid.jpg"; //本地路径(将图片直接存放在项目目录下)
Mat imgData = imread(imgPath.toLatin1().data()); //读取图片数据
cvtColor(imgData, imgData, COLOR_BGR2RGB); //图片格式转换
myImg = imgData;
myQImg = QImage((const unsigned char*)(imgData.data), imgData.cols, imgData.rows,
QImage::Format_RGB888);
imgShow();
}
显示图片的irngShow〇方法中只有一句:
void MainWindow::imgShow()
{
ui->labView->setPixmap(QPixmap::fromImage(
myQImg.scaled(ui->labView->size(), Qt::KeepAspectRatio))); //在Qt界面上显示图片
}
4.功能实现
找匹配物体的功能写在imgProc()方法中,本例采用相关匹配算法CV_TM_CCOEFF来匹配寻找画面中的一条小鱼,实现代码为:
void MainWindow::imgProc()
{
int METHOD = TM_CCOEFF;//(a)
Mat imgSrc = myImg;//将被显示的原图
QString imgPath = "fish.jpg"; //待匹配的子图(为原图上截取下的一部分)
Mat imgTmp = imread(imgPath.toLatin1().data());//读取图片数据
cvtColor(imgTmp, imgTmp, COLOR_BGR2RGB);//图片格式转换
Mat imgRes;
Mat imgDisplay;
imgSrc.copyTo(imgDisplay);
int rescols = imgSrc.cols - imgTmp.cols + 1;
int resrows = imgSrc.rows - imgTmp.rows + 1;
imgRes.create(rescols, resrows, CV_32FC1); //创建输出结果的矩阵
matchTemplate(imgSrc, imgTmp, imgRes, METHOD);//进行匹配
normalize(imgRes,imgRes,0,1,NORM_MINMAX,-1,Mat());//进行标准化
double minVal;
double maxVal;
Point minLoc;
Point maxLoc;
Point matchLoc;
minMaxLoc(imgRes,&minVal, &maxVal, &minLoc, &maxLoc, Mat());
//通过函数minMaxLoc定位最匹配的位置
//对于方法SQDIFF和SQDIFF_NORMED,数值越小匹配结果越好;而对于其他方法,数值越大, 匹配结果越好
if(METHOD == TM_SQDIFF || METHOD == TM_SQDIFF_NORMED)
matchLoc = minLoc;
else
matchLoc = maxLoc;
rectangle(imgDisplay, matchLoc, Point(matchLoc.x+imgTmp.cols, matchLoc.y + imgTmp.rows),
Scalar(255,0,0),2,8,0);
myQImg = QImage((const unsigned char*) (imgDisplay.data) , imgDisplay.cols, imgDisplay.rows,
QImage::Format_RGB888);
imgShow();//显示图片
}
其中,
(a) int METHOD = TM_CCOEFF: OpenCV通过函数matchTemplate实现了模板匹配算法,它共支持三大类6种不同算法。
- (1) TM_SQDIFF (方差匹配)、TM_SQDIFF_NORMED (标准方差匹配)
这类方法采用原图与待匹配子图像素的平方差来进行累加求和,计算所得数值越小,说明匹配度越高。
- (2) TM_CCORR (乘数匹配)、TM_CCORR_NORMED (标准乘数匹配)
这类方法采用原图与待匹配子图对应像素的乘积进行累加求和,与第一类方法相反,数值越大表示匹配度越高。
- (3) TM_CCOEFF (相关匹配)、TM_CCOEFF_NORMED (标准相关匹配)
这类方法把原图像素对其均值的相对值与待匹配子图像素对其均值的相对值进行比较,计算数值越接近1,表示匹配度越高。
通常来说,从匹配准确度上看,相关匹配要优于乘数匹配,乘数匹配则优于方差匹配,但这种准确度的提高是以增加计算复杂度和牺牲时间效率为代价的。如果所用计算机处理器速度较慢,则只能用比较简单的方差匹配算法;当所用设备处理器性能很好时,优先使用较复杂的相关匹配算法,可以保证识别准确无误。本例使用的是准确度最佳的TM_CCOEFF相关匹配算法。
最后,使界面上的按钮响应用户操作,在其单击事件过程中调用上面的处理方法:
void MainWindow::on_btnMatch_clicked()
{
imgProc();
}
5.运行结果
程序运行后,界面上初始显示美人鱼公主图片,单击“匹配”按钮,程序执行完匹配算法就会在图片上绘框标示出这条小鱼所在的位置,如图下所示。
————————————————
觉得有用的话请关注点赞,谢谢您的支持!
对于本系列文章相关示例完整代码有需要的朋友,可关注并在评论区留言!