当前位置:   article > 正文

OpenCV4.5 dnn模块+QT5.12.9实现人脸识别Demo_cv::facedetectoryn::create

cv::facedetectoryn::create

一、实现的效果

1.人脸检测

2.人脸识别

 也可以进行视屏的识别,但不知道怎么生成gif,在此不上图。

二、环境配置

1.下载Qt,openvc

QT:可能需要一个用户Download Qt | Develop Desktop & Embedded Systems | Qticon-default.png?t=LBL2https://www.qt.io/downloadOpenvc:Releases - OpenCVicon-default.png?t=LBL2https://opencv.org/releases/

 

2.配置过程

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:

1.模型初始化

opencv中基于DNN的人脸识别,是使用两个已经训练好的库来做的,一个人脸检测库,一个是人脸识别库。本文是初级的入门教程,所以不进行原理的解说,也不评价好坏

  1. // facealgo.h"
  2. #ifndef FACEALGO_H
  3. #define FACEALGO_H
  4. #include "iostream"
  5. #include "opencv2/opencv.hpp"
  6. #include "opencv2/dnn.hpp"
  7. #include <opencv2/core/utils/logger.hpp>
  8. #include <utility>
  9. struct faceInfo {
  10. std::string name;
  11. cv::Mat detResult;
  12. };
  13. class FaceAlgo {
  14. public:
  15. FaceAlgo();
  16. void initFaceModels(std::string detect_model_path, std::string recog_model_path, std::string face_db_dir);
  17. void detectFace(cv::Mat &frame, std::vector<std::shared_ptr<faceInfo>> &results, bool showFPS);
  18. void matchFace(cv::Mat &frame, std::vector<std::shared_ptr<faceInfo>> &results, bool l2=false);
  19. void registFace(std::string image_path, std::string name);
  20. void registFace(cv::Mat &cvImage,cv::Mat feature, std::string name);
  21. private:
  22. std::map<std::string, cv::Mat> face_models;
  23. cv::Ptr<cv::FaceDetectorYN> faceDetector;
  24. cv::Ptr<cv::FaceRecognizerSF> faceRecognizer;
  25. };
  26. #endif // FACEALGO_H

 在facealgo.h 中,定义了两个对象:

  1. cv::Ptr<cv::FaceDetectorYN> faceDetector;
  2. cv::Ptr<cv::FaceRecognizerSF> faceRecognizer;
faceDetector是一个opencv已经封装好的人脸识别检测器,faceRecognizer是opencv提供的人脸识别器。两个对象在进行使用前,分别需要利用已经训练好的模型进行初始化。模型下载可以在Github上Face DetectionFace Recognition两个位置,在gitee上也有OpenCV课程资料。模型的初始化函数(facealgo.cpp)定义如下:
  1. //facealgo.cpp
  2. void FaceAlgo::initFaceModels(std::string detect_model_path, std::string recog_model_path, std::string face_db_dir) {
  3. this->faceDetector = cv::FaceDetectorYN::create(detect_model_path, "", cv::Size(300, 300), 0.9f, 0.3f, 5000);
  4. this->faceRecognizer = cv::FaceRecognizerSF::create(recog_model_path, "");
  5. std::vector<std::string> fileNames;
  6. cv::glob(face_db_dir, fileNames);
  7. for(std::string file_path : fileNames){
  8. // cv::Mat image = cv::imread(file_path);
  9. int pos = static_cast<int>(file_path.find("\\"));
  10. std::string image_name = file_path.substr(pos+1, file_path.length() - pos - 5);
  11. this->registFace(file_path, image_name);
  12. std::cout<<"file name : " << image_name<< ".jpg"<<std::endl;
  13. }
  14. }

在我Demo的使用如下:

  1. QString fd_modelPath = "H:/temp/FaceReco/models/yunet.onnx";
  2. QString fr_modelPath = "H:/temp/FaceReco/models/face_recognizer_fast.onnx";
  3. QString face_db = "H:/temp/FaceReco/face_db/";
  4. //
  5. //判断模型模块是否存在
  6. if(QFileInfo(fd_modelPath).exists() || QFileInfo(fr_modelPath).exists())
  7. {
  8. faceAlgo->initFaceModels(fd_modelPath.toStdString(),fr_modelPath.toStdString(),face_db.toStdString());
  9. }
  10. else
  11. {
  12. QMessageBox warningBox(QMessageBox::Warning,tr("警告:"),tr("模型模块不存在!!!"));
  13. warningBox.show();
  14. //下面禁止功能按钮
  15. ui->btnDetect->setEnabled(false);
  16. ui->btnRegister->setEnabled(false);
  17. ui->btnRecognise->setEnabled(false);
  18. }

2. 人脸检测

基本思路如下:打开一张图片,利用人脸检测函数,检测图片中的人脸,进行人脸的标识。

项目中的实现代码如下:

  1. void MainWindow::on_btnDetect_clicked()
  2. {
  3. QStringList slResult = OpenImage();
  4. if(slResult.isEmpty())
  5. {
  6. ui->lbImg->setText("路径为空");
  7. return ;
  8. }
  9. QString filepath = slResult[0];
  10. QString fileMime = slResult[1];
  11. if(filepath != "")
  12. {
  13. if(fileMime.startsWith("image/"))
  14. {
  15. //获得当前label上的图片
  16. cv::Mat cvImg;
  17. //加载图片
  18. cvImg = cv::imread(filepath.toStdString());
  19. //检测图片中的人脸
  20. std::vector<std::shared_ptr<faceInfo>> results;
  21. faceAlgo->detectFace(cvImg,results,true);
  22. //显示人脸
  23. QImage qImg = this->cvMat2QImage(cvImg);
  24. // qDebug()<< ui->lbImg->size();
  25. //画个图
  26. QPainter qPtr(&qImg);
  27. qPtr.setPen(QPen(Qt::green, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
  28. int i = 0;
  29. for (auto item : results) {
  30. int x = int(item->detResult.at<float>(0,0));
  31. int y = int(item->detResult.at<float>(0,1));
  32. int w = int(item->detResult.at<float>(0,2));
  33. int h = int(item->detResult.at<float>(0,3));
  34. qPtr.drawRect(x,y,w,h);
  35. i++;
  36. }
  37. QPixmap qPmp = QPixmap::fromImage(qImg.scaled(ui->lbImg->size(), Qt::KeepAspectRatio));
  38. ui->lbImg->setScaledContents(false);
  39. ui->lbImg->setPixmap(qPmp);
  40. }
  41. else
  42. {
  43. cv::VideoCapture capture(filepath.toStdString());
  44. if(!capture.isOpened())
  45. {
  46. std::cout<<"video not open."<<std::endl;
  47. return;
  48. }
  49. int nFrame = 0;
  50. for (;;)
  51. {
  52. // Get frame
  53. cv::Mat frame;
  54. if (!capture.read(frame))
  55. {
  56. std::cerr << "Can't grab frame! Stop\n";
  57. break;
  58. }
  59. std::vector<std::shared_ptr<faceInfo>> results;
  60. faceAlgo->detectFace(frame,results,true);
  61. // //显示人脸
  62. QImage qImg = this->cvMat2QImage(frame);
  63. // // qDebug()<< ui->lbImg->size();
  64. // //画个图
  65. QPainter qPtr(&qImg);
  66. qPtr.setPen(QPen(Qt::green, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
  67. int i = 0;
  68. for (auto item : results) {
  69. int x = int(item->detResult.at<float>(0,0));
  70. int y = int(item->detResult.at<float>(0,1));
  71. int w = int(item->detResult.at<float>(0,2));
  72. int h = int(item->detResult.at<float>(0,3));
  73. qPtr.drawRect(x,y,w,h);
  74. i++;
  75. }
  76. QPixmap qPmp = QPixmap::fromImage(qImg.scaled(ui->lbImg->size(), Qt::KeepAspectRatio));
  77. ui->lbImg->setScaledContents(false);
  78. ui->lbImg->setPixmap(qPmp);
  79. int key = cv::waitKey(1);
  80. ++nFrame;
  81. if (key > 0)
  82. break;
  83. }
  84. //关闭视频,手动调用析构函数(非必须)
  85. capture.release();
  86. }
  87. }
  88. else
  89. {
  90. ui->lbImg->setText("路径为空");
  91. }
  92. }

3.人脸识别

人脸识别主要是利用已经识别的结果进行比对,从而获得识别结果。此处有个注册过程。就是告诉程序,某个特征的谁的问题。

  1. void MainWindow::on_btnRecognise_clicked()
  2. {
  3. QStringList slResult = OpenImage();
  4. if(slResult.isEmpty())
  5. {
  6. ui->lbImg->setText("路径为空");
  7. return ;
  8. }
  9. QString filepath = slResult[0];
  10. QString fileMime = slResult[1];
  11. if(filepath != "")
  12. {
  13. if(fileMime.startsWith("image/"))
  14. {
  15. //打开图像
  16. //获得当前label上的图片
  17. cv::Mat cvImg;
  18. //加载图片
  19. cvImg = cv::imread(filepath.toStdString());
  20. //检测图片中的人脸
  21. std::vector<std::shared_ptr<faceInfo>> faceResults;
  22. faceAlgo->detectFace(cvImg,faceResults,true);
  23. //匹配人脸
  24. faceAlgo->matchFace(cvImg,faceResults,false);
  25. //显示人脸
  26. QImage qImg = this->cvMat2QImage(cvImg);
  27. // qDebug()<< ui->lbImg->size();
  28. //画个图
  29. QPainter qPtr(&qImg);
  30. QPen rPen(Qt::red, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
  31. QPen gPen(Qt::green, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
  32. qPtr.setPen(gPen);
  33. qPtr.setFont(QFont("Times", 20, QFont::Bold));
  34. int i = 0;
  35. for (auto item : faceResults) {
  36. if(item->name != "Unknown")
  37. qPtr.setPen(gPen);
  38. else
  39. qPtr.setPen(rPen);
  40. int x = int(item->detResult.at<float>(0,0));
  41. int y = int(item->detResult.at<float>(0,1));
  42. int w = int(item->detResult.at<float>(0,2));
  43. int h = int(item->detResult.at<float>(0,3));
  44. qPtr.drawRect(x,y,w,h);
  45. qPtr.drawText(x+w/2,y+h+10,QString(item->name.c_str()));
  46. i++;
  47. }
  48. QPixmap qPmp = QPixmap::fromImage(qImg.scaled(ui->lbImg->size(), Qt::KeepAspectRatio));
  49. ui->lbImg->setScaledContents(false);
  50. ui->lbImg->setPixmap(qPmp);
  51. }
  52. else
  53. {
  54. cv::VideoCapture capture(filepath.toStdString());
  55. if(!capture.isOpened())
  56. {
  57. std::cout<<"video not open."<<std::endl;
  58. return;
  59. }
  60. int nFrame = 0;
  61. for (;;)
  62. {
  63. // Get frame
  64. cv::Mat frame;
  65. if (!capture.read(frame))
  66. {
  67. std::cerr << "Can't grab frame! Stop\n";
  68. break;
  69. }
  70. std::vector<std::shared_ptr<faceInfo>> results;
  71. faceAlgo->detectFace(frame,results,true);
  72. //匹配人脸
  73. faceAlgo->matchFace(frame,results,false);
  74. // //显示人脸
  75. //显示人脸
  76. QImage qImg = this->cvMat2QImage(frame);
  77. // qDebug()<< ui->lbImg->size();
  78. //画个图
  79. QPainter qPtr(&qImg);
  80. QPen rPen(Qt::red, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
  81. QPen gPen(Qt::green, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
  82. qPtr.setPen(gPen);
  83. qPtr.setFont(QFont("Times", 20, QFont::Bold));
  84. int i = 0;
  85. for (auto item : results) {
  86. if(item->name != "Unknown")
  87. qPtr.setPen(gPen);
  88. else
  89. qPtr.setPen(rPen);
  90. int x = int(item->detResult.at<float>(0,0));
  91. int y = int(item->detResult.at<float>(0,1));
  92. int w = int(item->detResult.at<float>(0,2));
  93. int h = int(item->detResult.at<float>(0,3));
  94. qPtr.drawRect(x,y,w,h);
  95. qPtr.drawText(x+w/2,y+h+10,QString(item->name.c_str()));
  96. i++;
  97. }
  98. QPixmap qPmp = QPixmap::fromImage(qImg.scaled(ui->lbImg->size(), Qt::KeepAspectRatio));
  99. ui->lbImg->setScaledContents(false);
  100. ui->lbImg->setPixmap(qPmp);
  101. int key = cv::waitKey(1);
  102. ++nFrame;
  103. if (key > 0)
  104. break;
  105. }
  106. //关闭视频,手动调用析构函数(非必须)
  107. capture.release();
  108. }
  109. }
  110. }

4.ui

ui设计比较简单,没有太多有难度的问题,此处不在进行单独的说明 。

四、代码的一些说明

由于水平有限,很多代码都很粗糙,欢迎指正。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/116191
推荐阅读
相关标签
  

闽ICP备14008679号