也可以进行视屏的识别,但不知道怎么生成gif,在此不上图。
QT:可能需要一个用户Download Qt | Develop Desktop & Embedded Systems | Qthttps://www.qt.io/downloadOpenvc:Releases - OpenCVhttps://opencv.org/releases/
1.在qt项目上右键->添加库
2.选择 外部库
3.点击 浏览-->打开opencv库的安装位置,我选择的vc14,因为我QT配置的是利用vc2019的编译器。所以直接用已经编译好的库,如果要用其他的编译方式,可能需要自己编译库。
3.添加头文件,添加路径到include,不要直接选择opencv2,主要原因是在后面利用一个源码的时候,会比较方便一些。直接包含到opencv2也是可以的,看个人喜欢。
实现过程主要是利用了B站OpenCV4 人脸检测与识别详解_哔哩哔哩_bilibili这条视屏中的源码以及opencv官方的示例(OpenCV: DNN-based face detection and recognition)。对UP主的源码没有进行大的改变,但从其提供的gitee上下载的源码有一个小bug,以下是下载源码(右)与我使用的代码(左)的diff:
opencv中基于DNN的人脸识别,是使用两个已经训练好的库来做的,一个人脸检测库,一个是人脸识别库。本文是初级的入门教程,所以不进行原理的解说,也不评价好坏。
// facealgo.h"
#ifndef FACEALGO_H
#define FACEALGO_H
#include "iostream"
#include "opencv2/opencv.hpp"
#include "opencv2/dnn.hpp"
#include
#include
struct faceInfo {
std::string name;
cv::Mat detResult;
};
class FaceAlgo {
public:
FaceAlgo();
void initFaceModels(std::string detect_model_path, std::string recog_model_path, std::string face_db_dir);
void detectFace(cv::Mat &frame, std::vector> &results, bool showFPS);
void matchFace(cv::Mat &frame, std::vector> &results, bool l2=false);
void registFace(std::string image_path, std::string name);
void registFace(cv::Mat &cvImage,cv::Mat feature, std::string name);
private:
std::map face_models;
cv::Ptr faceDetector;
cv::Ptr faceRecognizer;
};
#endif // FACEALGO_H
在facealgo.h 中,定义了两个对象:
cv::Ptr faceDetector;
cv::Ptr faceRecognizer;
faceDetector是一个opencv已经封装好的人脸识别检测器,faceRecognizer是opencv提供的人脸识别器。两个对象在进行使用前,分别需要利用已经训练好的模型进行初始化。模型下载可以在Github上Face Detection和Face Recognition两个位置,在gitee上也有OpenCV课程资料。模型的初始化函数(facealgo.cpp)定义如下:
//facealgo.cpp
void FaceAlgo::initFaceModels(std::string detect_model_path, std::string recog_model_path, std::string face_db_dir) {
this->faceDetector = cv::FaceDetectorYN::create(detect_model_path, "", cv::Size(300, 300), 0.9f, 0.3f, 5000);
this->faceRecognizer = cv::FaceRecognizerSF::create(recog_model_path, "");
std::vector fileNames;
cv::glob(face_db_dir, fileNames);
for(std::string file_path : fileNames){
// cv::Mat image = cv::imread(file_path);
int pos = static_cast(file_path.find("\\"));
std::string image_name = file_path.substr(pos+1, file_path.length() - pos - 5);
this->registFace(file_path, image_name);
std::cout<<"file name : " << image_name<< ".jpg"<
在我Demo的使用如下:
QString fd_modelPath = "H:/temp/FaceReco/models/yunet.onnx";
QString fr_modelPath = "H:/temp/FaceReco/models/face_recognizer_fast.onnx";
QString face_db = "H:/temp/FaceReco/face_db/";
//
//判断模型模块是否存在
if(QFileInfo(fd_modelPath).exists() || QFileInfo(fr_modelPath).exists())
{
faceAlgo->initFaceModels(fd_modelPath.toStdString(),fr_modelPath.toStdString(),face_db.toStdString());
}
else
{
QMessageBox warningBox(QMessageBox::Warning,tr("警告:"),tr("模型模块不存在!!!"));
warningBox.show();
//下面禁止功能按钮
ui->btnDetect->setEnabled(false);
ui->btnRegister->setEnabled(false);
ui->btnRecognise->setEnabled(false);
}
基本思路如下:打开一张图片,利用人脸检测函数,检测图片中的人脸,进行人脸的标识。
项目中的实现代码如下:
void MainWindow::on_btnDetect_clicked()
{
QStringList slResult = OpenImage();
if(slResult.isEmpty())
{
ui->lbImg->setText("路径为空");
return ;
}
QString filepath = slResult[0];
QString fileMime = slResult[1];
if(filepath != "")
{
if(fileMime.startsWith("image/"))
{
//获得当前label上的图片
cv::Mat cvImg;
//加载图片
cvImg = cv::imread(filepath.toStdString());
//检测图片中的人脸
std::vector> results;
faceAlgo->detectFace(cvImg,results,true);
//显示人脸
QImage qImg = this->cvMat2QImage(cvImg);
// qDebug()<< ui->lbImg->size();
//画个图
QPainter qPtr(&qImg);
qPtr.setPen(QPen(Qt::green, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
int i = 0;
for (auto item : results) {
int x = int(item->detResult.at(0,0));
int y = int(item->detResult.at(0,1));
int w = int(item->detResult.at(0,2));
int h = int(item->detResult.at(0,3));
qPtr.drawRect(x,y,w,h);
i++;
}
QPixmap qPmp = QPixmap::fromImage(qImg.scaled(ui->lbImg->size(), Qt::KeepAspectRatio));
ui->lbImg->setScaledContents(false);
ui->lbImg->setPixmap(qPmp);
}
else
{
cv::VideoCapture capture(filepath.toStdString());
if(!capture.isOpened())
{
std::cout<<"video not open."<> results;
faceAlgo->detectFace(frame,results,true);
// //显示人脸
QImage qImg = this->cvMat2QImage(frame);
// // qDebug()<< ui->lbImg->size();
// //画个图
QPainter qPtr(&qImg);
qPtr.setPen(QPen(Qt::green, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
int i = 0;
for (auto item : results) {
int x = int(item->detResult.at(0,0));
int y = int(item->detResult.at(0,1));
int w = int(item->detResult.at(0,2));
int h = int(item->detResult.at(0,3));
qPtr.drawRect(x,y,w,h);
i++;
}
QPixmap qPmp = QPixmap::fromImage(qImg.scaled(ui->lbImg->size(), Qt::KeepAspectRatio));
ui->lbImg->setScaledContents(false);
ui->lbImg->setPixmap(qPmp);
int key = cv::waitKey(1);
++nFrame;
if (key > 0)
break;
}
//关闭视频,手动调用析构函数(非必须)
capture.release();
}
}
else
{
ui->lbImg->setText("路径为空");
}
}
人脸识别主要是利用已经识别的结果进行比对,从而获得识别结果。此处有个注册过程。就是告诉程序,某个特征的谁的问题。
void MainWindow::on_btnRecognise_clicked()
{
QStringList slResult = OpenImage();
if(slResult.isEmpty())
{
ui->lbImg->setText("路径为空");
return ;
}
QString filepath = slResult[0];
QString fileMime = slResult[1];
if(filepath != "")
{
if(fileMime.startsWith("image/"))
{
//打开图像
//获得当前label上的图片
cv::Mat cvImg;
//加载图片
cvImg = cv::imread(filepath.toStdString());
//检测图片中的人脸
std::vector> faceResults;
faceAlgo->detectFace(cvImg,faceResults,true);
//匹配人脸
faceAlgo->matchFace(cvImg,faceResults,false);
//显示人脸
QImage qImg = this->cvMat2QImage(cvImg);
// qDebug()<< ui->lbImg->size();
//画个图
QPainter qPtr(&qImg);
QPen rPen(Qt::red, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
QPen gPen(Qt::green, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
qPtr.setPen(gPen);
qPtr.setFont(QFont("Times", 20, QFont::Bold));
int i = 0;
for (auto item : faceResults) {
if(item->name != "Unknown")
qPtr.setPen(gPen);
else
qPtr.setPen(rPen);
int x = int(item->detResult.at(0,0));
int y = int(item->detResult.at(0,1));
int w = int(item->detResult.at(0,2));
int h = int(item->detResult.at(0,3));
qPtr.drawRect(x,y,w,h);
qPtr.drawText(x+w/2,y+h+10,QString(item->name.c_str()));
i++;
}
QPixmap qPmp = QPixmap::fromImage(qImg.scaled(ui->lbImg->size(), Qt::KeepAspectRatio));
ui->lbImg->setScaledContents(false);
ui->lbImg->setPixmap(qPmp);
}
else
{
cv::VideoCapture capture(filepath.toStdString());
if(!capture.isOpened())
{
std::cout<<"video not open."<> results;
faceAlgo->detectFace(frame,results,true);
//匹配人脸
faceAlgo->matchFace(frame,results,false);
// //显示人脸
//显示人脸
QImage qImg = this->cvMat2QImage(frame);
// qDebug()<< ui->lbImg->size();
//画个图
QPainter qPtr(&qImg);
QPen rPen(Qt::red, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
QPen gPen(Qt::green, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
qPtr.setPen(gPen);
qPtr.setFont(QFont("Times", 20, QFont::Bold));
int i = 0;
for (auto item : results) {
if(item->name != "Unknown")
qPtr.setPen(gPen);
else
qPtr.setPen(rPen);
int x = int(item->detResult.at(0,0));
int y = int(item->detResult.at(0,1));
int w = int(item->detResult.at(0,2));
int h = int(item->detResult.at(0,3));
qPtr.drawRect(x,y,w,h);
qPtr.drawText(x+w/2,y+h+10,QString(item->name.c_str()));
i++;
}
QPixmap qPmp = QPixmap::fromImage(qImg.scaled(ui->lbImg->size(), Qt::KeepAspectRatio));
ui->lbImg->setScaledContents(false);
ui->lbImg->setPixmap(qPmp);
int key = cv::waitKey(1);
++nFrame;
if (key > 0)
break;
}
//关闭视频,手动调用析构函数(非必须)
capture.release();
}
}
}
ui设计比较简单,没有太多有难度的问题,此处不在进行单独的说明 。
由于水平有限,很多代码都很粗糙,欢迎指正。