嵌入式养成计划-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_OBJECTpublic: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 还是 -1recognizer->predict(face, lab, conf);if(lab != -1){// 匹配成功,给出提示,并关闭人脸检测定时器QMessageBox::information(this, "提示", "欢迎回来");ui->loginBtn->setEnabled(true);killTimer(check_timer_id);}}}}
}
相关文章:
嵌入式养成计划-47----QT--基于QT的OpenCV库实现人脸识别功能
一百二十一、基于QT的OpenCV库实现人脸识别功能 121.1 UI 界面 登录按钮现在没啥实际作用,因为没加功能,可以添加在识别成功后运行的功能代码 121.2 思路 显示人脸: 通过 VideoCapture 这个类下面的 open() 方法打开摄像头,对…...
MySQL(12):MySQL数据类型
MySQL中的数据类型 常见数据类型的属性: 整数类型 整数类型一共有 5 种,包括 TINYINT、SMALLINT、MEDIUMINT、INT(INTEGER)和 BIGINT。 CREATE TABLE test_int1 ( X TINYINT, y SMALLINT, z MEDIUMINT, m INT, n BIGINT );…...
哪款手机便签软件支持存储录音文件并支持转文字?
手机便签类软件带有存储录音转文字功能是比较实用的,很多人通常会整理很多录音类型的文件,录音文件整合在一起后,后续有需要可以逐条点开播放收听。尤其是在工作中,当领导说一些重点时,大家无法借助灵活的大脑来成功的…...
Health Kit申请验证有问题?解决方案全解析
在接入Health Kit的过程中,应用上线前需要完成申请验证环节,获得正式的运动健康权限。 我们贴心整理了申请验证被驳回的高频问题,您可以在申请前阅读以下内容,避免在您的申请材料中出现下述问题影响审核通过的进度哦!…...
2007-2022年上市公司工业机器人渗透度数据
2007-2022年上市公司工业机器人渗透度数据 1、时间:2007-2022年 2、指标:股票代码、年份、工业机器人渗透度 3、计算方式:首先,计算行业层面的工业机器人渗透度指标;其次,构建企业层面的工业机器人渗透度…...
k8s基础环境部署
目录 跨主机免密认证 禁用selinux--所有主机操作 1.使用sed 2.直接更改配置文件 3.重启才能生效 禁用swap--所有主机操作 网络参数调整--所有主机 部署docker环境--所有主机 1.配置软件源 2.安装最新版docker 3.设置开机自启 4.配置docker加速器 5.重启服务 cri环境…...
家用工作站方案:ThinkBook 14 2023 版
本篇文章聊聊今年双十一,我新购置的家用工作站设备:ThinkBook 14 2023,一台五千元价位,没有显卡的笔记本。我为什么选择它,它又能做些什么。 写在前面 2021 年年中的时候,我写过一篇《廉价的家用工作站方…...
电脑篇——本地串口转TCP,TCP转虚拟串口,网络调试助手,串口调试助手
TCP/UDP工具、串口工具 https://pan.baidu.com/s/1SY03d_RRVhyOZfsPlApmxg?pwd5555 今日有个需求,就是在本机电脑上接了一个串口设备,然后我的QtCreator是在内网远程电脑运行的,我想将串口设备“挂载”到远程电脑上去调试程序,于…...
igbt好坏判断方法有哪些?万用表怎么测试igbt的好坏?
什么是IGBT? IGBT即绝缘栅双极型晶体管,是一种复合全控型电压驱动式功率半导体器件,是电力控制和电力转换的核心器件,在高电压和高电流的光伏逆变器、储能装置和新能源汽车等领域被广泛应用。IGBT具有高输入阻抗,低导通压降&…...
Android UI 开发·界面布局开发·案例分析
目录 编辑 1. 线性布局(LinearLayout) 2. 相对布局(RelativeLayout) 3. 表格布局(TableLayout) 4. 帧布局(FrameLayout) 5. 网格布局(GridLayout࿰…...
2023-11-06 monetdb-事务-insert-delta缓存-分析
摘要: monetdb在事务处理时, 会将数据写入delta缓存中, 然后在commit时将数据写入wal文件, 随后由控制器决定何时将wal中的数据真正的写入BAT列文件中. 本文从delta缓存入手, 分析monetdb在事务处理中的细节. SQL: DML: create table t1 (a int); 事务DDL: START TRANSACTI…...
ubuntu 22.04 flameshot 截图异常的问题
方法找了好久,终于找到一个有用的 Firstly do not install flameshot from snapstore, install it using apt. Go to /etc/gdm3/custom.confRemove the comment on #WaylandEnablefalse Your custom.conf file should be like this: # GDM configuration storag…...
正点原子嵌入式linux驱动开发——Linux WIFI驱动
WIFI的使用已经很常见了,手机、平板、汽车等等,虽然可以使用有线网络,但是有时候很多设备存在布线困难的情况,此时WIFI就是一个不错的选择。正点原子STM32MP1开发板支持USB和SDIO这两种接口的WIFI,本章就来学习一下如何…...
React中的“状态”(state)和“属性”(props)的区别
在React中,"状态"(state)和"属性"(props)是两个重要的概念,它们在组件的生命周期和数据流中扮演着不同的角色。 状态(State): 状态是React组件中用…...
棋牌室电脑计时灯控,棋牌室计时灯控安装,佳易王计时计费管理系统软件
棋牌室电脑计时灯控,棋牌室计时灯控安装,佳易王计时计费管理系统软件 棋牌室的灯可以用佳易王计时计费软件来控制开关,当开始计时的时候,软件发送开灯的指令,灯打开,在结账后,软件发送关灯指令…...
P02项目诊断报警组件(学习操作日志记录、单元测试开发)
★ P02项目诊断报警组件 诊断报警组件的主要功能有: 接收、记录硬件设备上报的报警信息。从预先设定的错误码对照表中找到对应的声光报警和蜂鸣器报警策略,结合当前的报警情况对设备下发报警指示。将报警消息发送到消息队列,由其它组件发送…...
【ARM Trace32(劳特巴赫) 使用介绍 2 - Veloce 环境中使用trace32 连接 Cortex-M33】
请阅读【ARM Coresight SoC-400/SoC-600 专栏导读】 文章目录 T32MARM 介绍Trace32 .t32 和 .cmm 差异veloce 下启动TRACE321.1.3 TAP 状态机操作命令1.1.3.1 IDCODE(Identification Code)寄存器 介绍 T32MARM 介绍 T32MARM 是 Lauterbach 的 Trace32 …...
服务器硬件有哪些组成
服务器是由处理器、硬盘、内存、显卡、主板、网卡等组成,今天小编带大家了解一下服务器有哪些硬件吧! 1.最重要的当然就是处理器了,处理器就相当于是服务器的大脑,负责执行各种运算和指令,例如运行程序或者处理数据&am…...
【Git】Git基础命令操作速记
【Git】Git基础命令操作速记 文章目录 【Git】Git基础命令操作速记1. 初始化1.1 设置用户名和邮箱1.2 初始化仓库 2. 基础命令2.1 add和commit2.2 reset2.3 查看日志2.4 删除/找回本地仓库文件2.5 找回暂存区文件2.6 diff命令(找不同) 3. 分支命令3.1 查看分支3.2 创建分支3.3 …...
使用CDN有什么好处?
近年来,随着互联网的快速发展,越来越多的企业开始发展互联网业务,出现了各种各样的网站和web程序,互联网改变了人们的生活习惯与消费行为,人们也是越来越依赖网络,而这些改变让互联网产业得到更加迅速发展。…...
Cursor实现用excel数据填充word模版的方法
cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...
linux arm系统烧录
1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 (忘了有没有这步了 估计有) 刷机程序 和 镜像 就不提供了。要刷的时…...
(转)什么是DockerCompose?它有什么作用?
一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器。 Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...
实现弹窗随键盘上移居中
实现弹窗随键盘上移的核心思路 在Android中,可以通过监听键盘的显示和隐藏事件,动态调整弹窗的位置。关键点在于获取键盘高度,并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...
select、poll、epoll 与 Reactor 模式
在高并发网络编程领域,高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表,以及基于它们实现的 Reactor 模式,为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。 一、I…...
排序算法总结(C++)
目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指:同样大小的样本 **(同样大小的数据)**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...
使用SSE解决获取状态不一致问题
使用SSE解决获取状态不一致问题 1. 问题描述2. SSE介绍2.1 SSE 的工作原理2.2 SSE 的事件格式规范2.3 SSE与其他技术对比2.4 SSE 的优缺点 3. 实战代码 1. 问题描述 目前做的一个功能是上传多个文件,这个上传文件是整体功能的一部分,文件在上传的过程中…...
Monorepo架构: Nx Cloud 扩展能力与缓存加速
借助 Nx Cloud 实现项目协同与加速构建 1 ) 缓存工作原理分析 在了解了本地缓存和远程缓存之后,我们来探究缓存是如何工作的。以计算文件的哈希串为例,若后续运行任务时文件哈希串未变,系统会直接使用对应的输出和制品文件。 2 …...
门静脉高压——表现
一、门静脉高压表现 00:01 1. 门静脉构成 00:13 组成结构:由肠系膜上静脉和脾静脉汇合构成,是肝脏血液供应的主要来源。淤血后果:门静脉淤血会同时导致脾静脉和肠系膜上静脉淤血,引发后续系列症状。 2. 脾大和脾功能亢进 00:46 …...
41道Django高频题整理(附答案背诵版)
解释一下 Django 和 Tornado 的关系? Django和Tornado都是Python的web框架,但它们的设计哲学和应用场景有所不同。 Django是一个高级的Python Web框架,鼓励快速开发和干净、实用的设计。它遵循MVC设计,并强调代码复用。Django有…...
