赞
踩
也可以进行视屏的识别,但不知道怎么生成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 <opencv2/core/utils/logger.hpp>
- #include <utility>
- 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<std::shared_ptr<faceInfo>> &results, bool showFPS);
- void matchFace(cv::Mat &frame, std::vector<std::shared_ptr<faceInfo>> &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<std::string, cv::Mat> face_models;
- cv::Ptr<cv::FaceDetectorYN> faceDetector;
- cv::Ptr<cv::FaceRecognizerSF> faceRecognizer;
- };
-
-
- #endif // FACEALGO_H
在facealgo.h 中,定义了两个对象:
- cv::Ptr<cv::FaceDetectorYN> faceDetector;
- cv::Ptr<cv::FaceRecognizerSF> 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<std::string> fileNames;
- cv::glob(face_db_dir, fileNames);
- for(std::string file_path : fileNames){
- // cv::Mat image = cv::imread(file_path);
- int pos = static_cast<int>(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"<<std::endl;
- }
- }
在我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<std::shared_ptr<faceInfo>> 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<float>(0,0));
- int y = int(item->detResult.at<float>(0,1));
- int w = int(item->detResult.at<float>(0,2));
- int h = int(item->detResult.at<float>(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."<<std::endl;
- return;
- }
- int nFrame = 0;
- for (;;)
- {
- // Get frame
- cv::Mat frame;
- if (!capture.read(frame))
- {
- std::cerr << "Can't grab frame! Stop\n";
- break;
- }
-
-
- std::vector<std::shared_ptr<faceInfo>> 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<float>(0,0));
- int y = int(item->detResult.at<float>(0,1));
- int w = int(item->detResult.at<float>(0,2));
- int h = int(item->detResult.at<float>(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<std::shared_ptr<faceInfo>> 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<float>(0,0));
- int y = int(item->detResult.at<float>(0,1));
- int w = int(item->detResult.at<float>(0,2));
- int h = int(item->detResult.at<float>(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."<<std::endl;
- return;
- }
- int nFrame = 0;
- for (;;)
- {
- // Get frame
- cv::Mat frame;
- if (!capture.read(frame))
- {
- std::cerr << "Can't grab frame! Stop\n";
- break;
- }
-
-
- std::vector<std::shared_ptr<faceInfo>> 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<float>(0,0));
- int y = int(item->detResult.at<float>(0,1));
- int w = int(item->detResult.at<float>(0,2));
- int h = int(item->detResult.at<float>(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设计比较简单,没有太多有难度的问题,此处不在进行单独的说明 。
由于水平有限,很多代码都很粗糙,欢迎指正。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。