嵌入式养成计划-47----QT--基于QT的OpenCV库实现人脸识别功能

news2024/11/24 9:04:49

一百二十一、基于QT的OpenCV库实现人脸识别功能

121.1 UI 界面 在这里插入图片描述

在这里插入图片描述
登录按钮现在没啥实际作用,因为没加功能,可以添加在识别成功后运行的功能代码

121.2 思路

  • 显示人脸: 通过 VideoCapture 这个类下面的 open() 方法打开摄像头,对摄像头读取到的图像帧进行处理。调整人脸图像尺寸,将人脸图像放到矩形框容器中,再将这个图像显示到UI界面上
  • 录入人脸: 加载或者创建级联分类器文件(有就是加载,没有就是创建)。对当前图形依次进行灰度处理、均衡化处理,然后放到容器里面,每张人脸对应的标签也放进去(虽然都是1),可以自己设定往容器里面放多少张图像帧。当放完之后就可以转化为人脸模型了,存完人脸模型就可以选择进行验证(即人脸检测识别)。顺手将人脸容器和标签容器清空。
  • 人脸识别: 打开人脸模型文件,打开成功后将当前视频帧依次进行灰度处理和均衡化处理,然后根据设置的人脸可信度进行识别,识别成功后就提示识别成功。

121.3 代码

main.cpp

#include "faceidentification.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    faceIdentification w;
    w.show();

    return a.exec();
}

faceidentification.h

#ifndef FACEIDENTIFICATION_H
#define FACEIDENTIFICATION_H

#include <QWidget>

#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>
#include <opencv2/face.hpp>
#include <vector>
#include <map>
#include <QMessageBox>
#include <QDebug>
#include <QFile>
#include <QTextStream>
#include <QDateTime>
#include <QTimerEvent>
#include <QtSerialPort/QtSerialPort>
#include <QtSerialPort/QSerialPortInfo>
using namespace  cv;
using namespace cv::face;
using namespace std;

namespace Ui {
class faceIdentification;
}

class faceIdentification : public QWidget
{
    Q_OBJECT

public:
    explicit faceIdentification(QWidget *parent = 0);
    ~faceIdentification();

signals:
    //  加载配置文件与保存人脸模型文件 的信号
    void load_CascadeClassifier_and_create_face_file_SIGNAL();


public slots:
    //  加载配置文件与人脸模型文件 的槽函数声明
    void load_CascadeClassifier_and_create_face_file_SLOT();

private slots:
    //  打开摄像头对应的槽函数声明
    void on_openBtn_clicked();

    //  关闭摄像头对应的槽函数声明
    void on_closeBtn_clicked();

    //  开始录入对应的槽函数声明
    void on_inputBtn_clicked();

private:
    Ui::faceIdentification *ui;

    //  摄像头相关成员
    //  视频对象
    VideoCapture v;
    //  图像容器,存放图片帧
    Mat src;    //  摄像头直接摄入的图像
    Mat gray;   //  转换成的灰度图
    Mat dst;    //  灰度图转换成的灰度直方图
    Mat rgb;    //  摄像头摄入的BGR转换的RGB图像

    //  级联分类器对象
    CascadeClassifier c;

    //  人脸矩形框容器
    vector<Rect> faces;

    //  重写的定时器超时事件处理函数
    void timerEvent(QTimerEvent *event) override;

    //  打开摄像头的定时器
    int camer_timer_id;

    /***  人脸录入的相关成员  ***/
    //  人脸录入的定时器
    int study_timer_id;
    //  人脸识别器指针
    Ptr<LBPHFaceRecognizer> recognizer;
    //  存储人脸图像帧的容器
    vector<Mat> study_faces;
    //  存放人脸图像帧对应的标签
    vector<int> study_labs;
    //  保存人脸图像帧的次数
    int count = 0;

    //  用于控制是人脸录入还是人脸检测
    bool input_flag = false;
    bool check_flag = false;

    //  人脸检测的定时器
    int check_timer_id;
};

#endif // FACEIDENTIFICATION_H

faceidentification.cpp

#include "faceidentification.h"
#include "ui_faceidentification.h"

faceIdentification::faceIdentification(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::faceIdentification)
{
    ui->setupUi(this);
    //  将自定义的 加载配置文件与保存人脸模型文件 的信号与槽函数进行连接
    connect(this, &faceIdentification::load_CascadeClassifier_and_create_face_file_SIGNAL,
            this,&faceIdentification::load_CascadeClassifier_and_create_face_file_SLOT);

    //  初始化UI界面
    ui->closeBtn->setEnabled(false);
    ui->inputBtn->setEnabled(false);
    ui->loginBtn->setEnabled(false);
}

faceIdentification::~faceIdentification()
{
    delete ui;
}

//  加载配置文件与人脸模型文件 的槽函数实现
void faceIdentification::load_CascadeClassifier_and_create_face_file_SLOT()
{
    //  加载级联分类器配置文件
    if(!c.load("D:\\opencv\\heads\\haarcascade_frontalface_alt.xml")){
        QMessageBox::warning(this,"警告","级联分类器加载失败");
        return ;
    }

    //  人脸模型文件
    QFile faceFile("D:\\opencv\\heads\\my_face.xml");
    //  如果人脸模型存在,则加载;若不存在,则创建
    if(faceFile.exists()){
        recognizer = LBPHFaceRecognizer::load<LBPHFaceRecognizer>("D:\\opencv\\heads\\my_face.xml");
    }else{
        recognizer = LBPHFaceRecognizer::create();
    }
}

//  打开摄像头对应的槽函数实现
void faceIdentification::on_openBtn_clicked()
{
    //  打开摄像头
    if(!v.open(0)){
        QMessageBox::warning(this,"警告","摄像头打开失败");
        return ;
    }

    //  发射 加载配置文件与保存人脸模型文件 的信号
    emit load_CascadeClassifier_and_create_face_file_SIGNAL();

    //  启动计时器,用于在UI界面上显示人脸
    camer_timer_id = startTimer(20);

    //  更改UI按钮可用性
    ui->closeBtn->setEnabled(true);
    ui->inputBtn->setEnabled(true);
    ui->openBtn->setEnabled(false);

    //  启动人脸检测定时器
    check_timer_id = startTimer(1000);

    //  表示只进行人脸检测
    check_flag = true;

    //  设置人脸检测可信度,低于100表示检测成功
    recognizer->setThreshold(100);
}

//  关闭摄像头对应的槽函数实现
void faceIdentification::on_closeBtn_clicked()
{
    //  关闭摄像头
    v.release();
    //  关闭定时器
    killTimer(camer_timer_id);

    //  更改UI按钮可用性
    ui->closeBtn->setEnabled(false);
    ui->inputBtn->setEnabled(false);
    ui->openBtn->setEnabled(true);
    ui->label->clear();

}

//  人脸录入按钮对应的槽函数实现
void faceIdentification::on_inputBtn_clicked()
{
    //  进行人脸录入,而不是识别
    input_flag = true;
    check_flag = false;

    //  初始化人脸录入次数
    count = 0;

    //  启动人脸录入定时器
    study_timer_id = startTimer(50);

    //  将人脸录入按钮设置为不可用状态
    ui->inputBtn->setEnabled(false);
}

//  定时器超时事件处理函数
void faceIdentification::timerEvent(QTimerEvent *event)
{
    //  打开摄像头的定时器超时
    if(camer_timer_id == event->timerId()){
        //  从摄像头中读取图像放到src中
        v.read(src);
        //  将读取进来的镜像图像进行翻转
        flip(src, src, 1);
        //  将opencv的 BGR 图像转换为 RGB 图像
        cvtColor(src, rgb, CV_BGR2RGB);

        //  调整 RGB 图像的尺寸,使其能够正好放进UI界面的图像框中
        cv::resize(rgb, rgb, Size(ui->label->width(), ui->label->height()));
        //  将 RGB 图像转换为灰度图,再转换为灰度直方图(均衡化处理)
        cvtColor(rgb, gray, CV_BGR2GRAY);
        equalizeHist(gray, dst);

        //  将图像上的人脸放到矩形框容器中
        c.detectMultiScale(dst, faces);

        //  将矩形框绘制到人脸上
        for(int i=0; i<faces.size(); i++){
            rectangle(rgb, faces[i], Scalar(255, 0, 0), 2);
        }

        //  定义一个QImage对象,用于将图像放到UI界面上
        QImage img(rgb.data, rgb.cols, rgb.rows, rgb.cols*rgb.channels(), QImage::Format_RGB888);
        ui->label->setPixmap(QPixmap::fromImage(img));
    }

    //  人脸录入定时器超时
    if(study_timer_id == event->timerId()){
        qDebug() << "正在录入,请正对摄像头";
        if(input_flag){
            //  存储当前图像
            Mat face;
            //  将从视频中读取来的图像存起来
            face = src(faces[0]);
            //  灰度处理
            cvtColor(face, face, CV_BGR2GRAY);
            //  灰度直方图(均衡化处理)
            equalizeHist(face, face);
            //  保存起来,放到容器中
            study_faces.push_back(face);
            study_labs.push_back(1);

            count++;

            //  存了五十张
            if(50 == count){
                //  将五十张人脸转换为数据模型存起来
                recognizer->update(study_faces, study_labs);
                recognizer->save("D:\\opencv\\heads\\my_face.xml");

                QMessageBox::information(this, "提示", "人脸录入成功");

                //  可以进行人脸检测,而不是录入了
                check_flag = true;
                input_flag = false;

                //  清空容器及相关变量,以待下次使用
                study_faces.clear();
                study_labs.clear();
                count = 0;

                //  关闭人脸录入定时器
                killTimer(study_timer_id);
            }
        }
    }

    //  人脸检测识别定时器超时
    if(check_timer_id == event->timerId()){
        qDebug() << "正在检测";
        if(check_flag){
            QFile faceFile("D:\\opencv\\heads\\my_face.xml");
            if(faceFile.exists()){
                //  将视频中的一帧人脸图像放到face中
                Mat face;
                face = src(faces[0]);
                //  灰度处理
                cvtColor(face, face, CV_BGR2GRAY);
                //  均衡化处理
                equalizeHist(face, face);

                //  假设匹配后的结果
                int lab = -1;
                double conf = 0.0;

                //  如果匹配成功,则 lab 不再是 -1;若匹配失败,则 lab 还是 -1
                recognizer->predict(face, lab, conf);
                if(lab != -1){
                    //  匹配成功,给出提示,并关闭人脸检测定时器
                    QMessageBox::information(this, "提示", "欢迎回来");
                    ui->loginBtn->setEnabled(true);
                    killTimer(check_timer_id);
                }
            }
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1187146.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

算法进阶指南图论 最优贸易

最优贸易 题目描述 C C C 国有 n n n 个大城市和 m m m 条道路&#xff0c;每条道路连接这 n n n 个城市中的某两个城市。任意两个城市之间最多只有一条道路直接相连。这 m m m 条道路中有一部分为单向通行的道路&#xff0c;一部分为双向通行的道路&#xff0c;双向通行的…

大语言模型比武

今年随着 ChatGPT 的流行&#xff0c;并在各个领域有一定程度生产级别的应用。国内外也掀起了一股大语言模型浪潮&#xff0c;各大厂商都推出了自己的大语言模型&#xff0c;阿里推出了 通义千问&#xff0c;腾讯推出了 Hunyuan&#xff0c;亚马逊云推出了 Titan&#xff0c;大…

Ubuntu22.04安装MySql

在Ubuntu上安装mysql就比较简单了 1、常规操作&#xff0c;更新软件包列表 apt update 至少安装之前看一眼版本吧 apt list mysql-server 嗯&#xff0c;是8.0.35版本的 2、安装mysql apt install mysql-server 3、给root用户设置密码 # 第一次安装完无需密码,让你输入…

MathType2024优秀的数学公式编辑工具

数学是许多学科中必不可少的一部分&#xff0c;而数学公式在学术和科学领域使用广泛。然而&#xff0c;许多人在创建和编辑数学公式时面临困难。 作为软件开发人员&#xff0c;在编写技术文档时通常也会需要输入一些复杂数学、物理公式&#xff0c;而 Word 中的公式编辑有时使…

PCL ICP点云精配准(点到面)

文章目录 一、简介二、PCL中的类型三、实现代码四、实现效果参考资料一、简介 ICP算法总共分为6个阶段,如下图所示: (1)挑选发生重叠的点云子集,这一步如果原始点云数据量比较巨大,一般会对原始点云进行下采样操作。 (2)匹配特征点。通常是距离最近的两个点,当然这需要…

【PHP】医院HIS手术麻醉临床信息管理系统源码 实现术前、术中、术后全流程管理

手术麻醉系统是一套以数字形式与医院信息系统&#xff08;如HIS、EMR、LIS、PACS等&#xff09;和医疗设备等软、硬件集成并获取围手术期相关信息的计算机系统&#xff0c;其核心是对围手术期患者信息自动采集、储存、分析并呈现。该系统通过整合围手术期中病人信息、人员信息、…

windows11使用docker部署安装minio

时间 2023-11-08 windows11使用docker部署安装minio 目录 1.docker 下载镜像2.docker安装镜像3.访问控制台4.安装问题解决5.使用教程 1.docker 下载镜像 调整镜像源到国内&#xff0c;否则会很慢 docker pull minio/minio2.docker安装镜像 设置用户名和密码时需要注意&…

Flutter android和ios闪屏页配置

一.概念理解 闪屏页 1.当点击app开始的一瞬间&#xff0c;所呈现出来的页面就是闪屏页。 2.为什么会有闪屏也&#xff0c;由于app启动需要加载代码&#xff0c;这个过程需要耗时&#xff0c;在没有加载完成之前&#xff0c;是看不到app真正的页面。所以app在没有完全加载完时…

22款奔驰GLE450升级23P驾驶辅助 智能L2领航

驾驶辅助和自动驾驶的区别就是需要人为去接管&#xff0c;虽然车辆会根据道路自己行驶&#xff0c;弯道上也能居中自动修正行驶&#xff0c;长时间不接管方向盘&#xff0c;系统会提示人为接管&#xff0c;这就是奔驰的23P驾驶辅助系统&#xff0c; 很多车友升级23P驾驶辅助系统…

Power Apps-创建表头样式

点击上方插入中的文本标签&#xff0c;双击编辑文字&#xff0c;右侧边栏可以编辑样式&#xff08;颜色中第一个选择字体颜色&#xff0c;第二个选择组件背景色&#xff09;

PTA_乙级_1001_C++

思路&#xff1a;使用判断语句即可&#xff0c;使用while进行循环&#xff0c;终止条件是n不等于1&#xff0c;然后用if-else判断奇数偶数 #include <iostream> using namespace std;int main(){int n;int count0;cin>>n;while(n!1){if(n%20){n/2;}else{n3*n1;n/2…

画图、图片处理

这里写目录标题 画图问题代码d2l.plt.subplots返回值axes d2l.plt.subplots(num_rows, num_cols, figsizefigsize&#xff09;subplot()、subplots()python内置函数&#xff1a;zip()函数搭配enumerate函数使用&#xff0c;用在for循环中简介enumerate()简介zip() transforms.…

PHP代码示例

我们需要使用PHP的curl库来发送HTTP请求。以下是一个基本的示例&#xff1a; php <?php // 初始化curl $ch curl_init(); // 设置代理 curl_setopt($ch, CURLOPT_PROXY, ""); // 设置URL curl_setopt($ch, CURLOPT_URL, ""); // 执行请求 $respon…

使用request库的get方法发起GET请求

// 导入所需的库 const request require(request); const cheerio require(cheerio);// 设置代理信息&#xff0c;proxy_host: www.duoip.cn, proxy_port: 8000 const proxy {host: jshk.com.cn,port: 1234 };// 定义要爬取的URL const url http://localhost:9200/_cat/ind…

Mysql配置主从复制-GTID模式

目录 主从复制 主从复制的定义 主从复制的原理 主从复制的优势 主从复制的形式 主从复制的模式 主从复制的类型 GTID模式 GTID的概念 GTID的优势 GTID的原理 GTID的配置 Mysql主服务器 ​编辑 Mysql从服务器 ​编辑 主从复制 主从复制的定义 是指把数据从一个…

rank()、row_number()、dense_rank()用法详解

建表测试 测试表数据&#xff1a;test1 CREATE DATABASE /*!32312 IF NOT EXISTS*/db_test /*!40100 DEFAULT CHARACTER SET utf8 */; USE db_test; /*Table structure for table test1 */ DROP TABLE IF EXISTS test1; CREATE TABLE test1 ( id int(10) NOT NULL, score i…

Go语言的Json序列化与反序列化、Goto语法、Tcp Socket通信

目录标题 一、Json序列化与反序列化1. 序列化2. 反序列化 二、Goto语法三、Tcp Socket1. 单客户端发送信息到服务端2. 服务端客户端通信 一、Json序列化与反序列化 1. 序列化 package mainimport ("encoding/json""fmt")type Person struct {Name string…

【uniapp】六格验证码输入框实现

效果图 代码实现 <view><view class"tips">已发送验证码至<text class"tips-phone">{{ phoneNumber }}</text></view><view class"code-input-wrap"><input class"code-input" v-model"…

fpga时序相关概念与理解

一、基本概念理解 对于数字系统而言&#xff0c;建立时间&#xff08;setup time&#xff09;和保持时间&#xff08;hold time&#xff09;是数字电路时序的基础。数字电路系统的稳定性&#xff0c;基本取决于时序是否满足建立时间和保持时间。 建立时间Tsu&#xff1a;触发器…

【第2章 Node.js基础】2.1 JavaScript基本语法

文章目录 学习目标JavaScript版本与JavaScript运行环境JavaScript版本JavaScript运行环境 JavaScript语句与注释语句语句块注释 变量变量的命名变量的声明与赋值变量提升变量泄露全局作用域和函数作用域块级作用域与let关键字使用const关键字声明只读常量注意 数据类型数值&…