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

一百二十一、基于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);
                }
            }
        }
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

进口猫罐头在排行榜中是否靠前?排行榜中靠前的猫罐头测评

养猫这6年&#xff0c;我对猫咪的日常饮食把关一直很严格。这些年我给我家猫们购买过很多不同品牌、不同口味的罐头&#xff0c;在猫罐头的挑选、分析上还是有一些经验的。今天&#xff0c;我将和大家一起探讨进口猫罐头在排行榜中是否靠前&#xff1f;同时&#xff0c;我将为大…

优化VMD全家桶!

↖加关注这种话银家怎么好意思说出口嘛-- 声明&#xff1a;对于作者的原创代码&#xff0c;禁止转售倒卖&#xff0c;违者必究&#xff01; 本期对以往智能算法优化VMD的代码做一个总结。 代码目录 优化VMD全家桶&#xff01;&#xff1a;https://mbd.pub/o/bread/ZZaVlp5xVMD为…

SAP CK51N销售订单取关联采购订单价格增强

需求fs 销售订单及行项目 enhancement 测试

微服务-我对Spring Clound的理解

官网&#xff1a;https://spring.io/projects/spring-cloud 官方说法&#xff1a;Spring Cloud 为开发人员提供了快速构建分布式系统中一些常见模式的工具&#xff08;例如配置管理、服务发现、熔断器、智能路由、微代理、控制总线、一次性令牌、全局锁、领导选举、分布式会话…

什么是Node.js的调试器(debugger)工具?

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

力扣第1035题 不相交的线中等 c++ (最长公共子序列) 动态规划 附Java代码

题目 1035. 不相交的线 中等 相关标签 数组 动态规划 在两条独立的水平线上按给定的顺序写下 nums1 和 nums2 中的整数。 现在&#xff0c;可以绘制一些连接两个数字 nums1[i] 和 nums2[j] 的直线&#xff0c;这些直线需要同时满足满足&#xff1a; nums1[i] nums2[j]…

uni-app前端H5页面底部内容被tabbar遮挡

问题&#xff1a; 在用uniapp写小程序的时候&#xff0c;底部有一部分内容没显示出来&#xff0c;被底部的tabbar遮挡住了 解决&#xff1a; 给最外部的view设置样式padding-bottom: var(--window-bottom)&#xff0c;如下 参考&#xff1a; 参考1 参考2 使用 uni-app 框…

idea Plugins 搜索不到插件

Settings — System Settings — HTTP Proxy&#xff0c;打开HTTP Proxy 页面&#xff0c;设置自动发现代理&#xff1a; 勾选Atuto-detect proxy settings&#xff0c;勾选Automatic proxy configuration URL&#xff0c;输入&#xff1a; https://plugins.jetbrains.com/id…

Julia绘图初步:Plots

文章目录 基础绘图绘图类型点线参数三维绘图 Julia开发环境 基础绘图 Julia中最常用的绘图模块自然是Plots&#xff0c;点击]进入安装模式后&#xff0c;输入add Plots即可安装&#xff0c;装完之后按下退格键回到Julia环境&#xff0c;就可以调用了 using Plots x 0:0.1:1…

【2023-11-09】git使用随记——gitignore文件配置某些文件忽略

git使用随记——gitignore文件配置某些文件忽略 通过git进行版本控制在项目中是非常常见的&#xff0c;一些项目构建上的文件通常是不需要进行版本控制的&#xff0c;也就无需推送到git仓库中&#xff0c;比如前端项目中的node_module目录。提供配置.gitignore文件 但是某些情…

Android Studio代码无法自动补全

Android Studio代码自动无法补全问题解决 在写layout布局文件时&#xff0c;代码不提示&#xff0c;不自动补全&#xff0c;可以采用如下方法&#xff1a; 点击File—>Project Structure&#xff0c;之后如图所示&#xff0c;找到左侧Modules&#xff0c;修改SDK版本号&…

Python基础教程之十九:Python优先级队列示例

1.什么是优先队列 优先级队列是一种抽象数据类型&#xff0c;类似于常规队列或堆栈数据结构&#xff0c;但每个元素还具有与之关联的“优先级”。在优先级队列中&#xff0c;优先级高的元素先于优先级低的元素提供。如果两个元素具有相同的优先级&#xff0c;则将根据其在队列…

【C语言 | 预处理】C语言预处理详解(一) —— #define、#under、#if、#else、#elif、#endif、#include、#error

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…

mac M2 pytorch_geometric安装

我目前的环境是mac M2&#xff0c;我在base环境中安装了pytorch_geometric,仅仅做测试用的&#xff0c;不做真正跑代码的测试 首先我的base环境的设置如下&#xff1a; pip install pyg_lib torch_scatter torch_sparse torch_cluster torch_spline_conv -f https://data.pyg.…

Tomcat隐藏版本号和关闭默认管理页面

一. 隐藏Tomcat异常页面中的版本信息&#xff0c;Tomcat服务器版本号泄露 Tomcat/8.5.xx相关版本号等信息&#xff0c;是不安全的。这会被黑客获取到&#xff0c;利用该版本的其他漏洞对服务器进行异常操作&#xff0c;所以需要隐藏掉。 进入tomcat安装目录 apache-tomcat-8.…

Leetcode2246. 相邻字符不同的最长路径

Every day a Leetcode 题目来源&#xff1a;2246. 相邻字符不同的最长路径 解法1&#xff1a;树形 DP 如果没有相邻节点的限制&#xff0c;那么本题求的就是树的直径上的点的个数&#xff0c;见于Leetcode543. 二叉树的直径。 考虑用树形 DP 求直径。 枚举子树 x 的所有子…

vue项目使用pcl.js展示.pcd/.bin点云文件

vue项目使用pcl展示.pcd/.bin点云文件 1.安装pcl.js2.在页面引入pcl及相关js3.开始实例化4.绘制画布注意&#xff1a;报错原因大部分是因为版本改动函数或者方法导致找不到函数或者方法&#xff0c;注意版本&#xff01;&#xff01;&#xff01; 1.安装pcl.js npm install pc…

淘宝天猫京东苏宁1688等平台关键词监控价格API接口(店铺商品价格监控API接口调用展示)

淘宝天猫京东苏宁1688等平台关键词监控价格API接口&#xff08;店铺商品价格监控API接口调用展示&#xff09;代码对接如下&#xff1a; item_get-获得淘宝商品详情 公共参数 请求地址: https://o0b.cn/anzexi 名称类型必须描述keyString是调用key&#xff08;必须以GET方式…

Java / Android 多线程和 synchroized 锁

s AsyncTask 在Android R中标注了废弃 synchronized 同步 Thread: thread.start() public synchronized void start() {/*** This method is not invoked for the main method thread or "system"* group threads created/set up by the VM. Any new functionali…

雅创电子-301099 三季报分析(20231109)

雅创电子-301099 基本情况 公司名称&#xff1a;上海雅创电子集团股份有限公司 A股简称&#xff1a;雅创电子 成立日期&#xff1a;2008-01-14 上市日期&#xff1a;2021-11-22 所属行业&#xff1a;批发业 周期性&#xff1a;0 主营业务&#xff1a;分销东芝、首尔半导体、村田…