OpenCV4.5 dnn模块+QT5.12.9实现人脸识别Demo

一、实现的效果

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的人脸识别,是使用两个已经训练好的库来做的,一个人脸检测库,一个是人脸识别库。本文是初级的入门教程,所以不进行原理的解说,也不评价好坏

// 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 DetectionFace 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);
    }

2. 人脸检测

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

项目中的实现代码如下:

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("路径为空");
    }
}

3.人脸识别

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


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();
        }
    }
}

4.ui

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

四、代码的一些说明

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

  • 2
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值