STM32全栈嵌入式人脸识别考勤系统:融合OpenCV、Qt和SQLite的解决方案

1. 项目概述

本项目旨在设计并实现一个基于STM32的全栈人脸识别考勤系统。该系统结合了嵌入式开发、计算机视觉和数据库技术,实现了自动人脸检测、识别和考勤记录功能。

主要特点:

  • 使用STM32F4系列微控制器作为主控制器
  • 采用OpenCV进行人脸检测和识别
  • Qt开发跨平台桌面应用程序,实现友好的用户界面
  • SQLite嵌入式数据库存储员工信息和考勤记录
  • 支持实时考勤、数据统计分析和报表生成

2. 系统设计

2.1 硬件设计

主要硬件模块及功能:

  • STM32F407VGT6微控制器:系统的核心,负责协调各个模块工作
  • OV7670摄像头模块:捕获实时图像,用于人脸检测和识别
  • 3.5寸TFT LCD显示屏:显示系统界面和识别结果
  • AS608指纹识别模块:作为辅助识别手段
  • RC522 RFID读卡器:用于员工卡识别,提供备用签到方式
  • ESP8266 WiFi模块:实现与服务器的无线通信,上传考勤数据

2.2 软件设计

3. 代码实现

3.1 人脸检测

以下是使用OpenCV实现人脸检测的代码示例:

#include <opencv2/opencv.hpp>
#include <opencv2/objdetect.hpp>using namespace cv;class FaceDetector {
private:CascadeClassifier face_cascade;public:FaceDetector(const std::string& cascade_file) {// 加载Haar级联分类器if (!face_cascade.load(cascade_file)) {throw std::runtime_error("Error loading face cascade file");}}std::vector<Rect> detectFaces(const Mat& frame) {Mat gray;std::vector<Rect> faces;// 转换为灰度图像cvtColor(frame, gray, COLOR_BGR2GRAY);// 执行人脸检测face_cascade.detectMultiScale(gray, faces, 1.1, 3, 0, Size(30, 30));return faces;}void drawFaces(Mat& frame, const std::vector<Rect>& faces) {for (const auto& face : faces) {rectangle(frame, face, Scalar(255, 0, 0), 2);}}
};

代码说明:

  1. FaceDetector类封装了人脸检测功能。
  2. 构造函数加载Haar级联分类器文件。
  3. detectFaces方法接收一帧图像,返回检测到的人脸矩形区域。
  4. drawFaces方法在原图上绘制检测到的人脸矩形框。

 

3.2 人脸识别

下面是使用LBPH算法实现人脸识别的代码示例:

#include <opencv2/face.hpp>
#include <opencv2/opencv.hpp>using namespace cv;
using namespace cv::face;class FaceRecognizer {
private:Ptr<LBPHFaceRecognizer> model;public:FaceRecognizer() {model = LBPHFaceRecognizer::create();}void train(const std::vector<Mat>& faces, const std::vector<int>& labels) {model->train(faces, labels);}void predict(const Mat& face, int& label, double& confidence) {model->predict(face, label, confidence);}void saveModel(const std::string& filename) {model->save(filename);}void loadModel(const std::string& filename) {model->read(filename);}
};

代码说明:

  1. FaceRecognizer类封装了LBPH人脸识别器的功能。
  2. 构造函数创建LBPH人脸识别器实例。
  3. train方法用于训练模型。
  4. predict方法进行人脸识别,返回预测的标签和置信度。
  5. saveModelloadModel方法用于保存和加载训练好的模型。

3.3 数据库操作

使用SQLite进行数据库操作的代码示例:

#include <sqlite3.h>
#include <string>
#include <stdexcept>
#include <iostream>class Database {
private:sqlite3* db;static int callback(void* data, int argc, char** argv, char** azColName) {// 处理查询结果的回调函数for(int i = 0; i < argc; i++) {std::cout << azColName[i] << " = " << (argv[i] ? argv[i] : "NULL") << std::endl;}std::cout << std::endl;return 0;}public:Database(const std::string& dbName) {if (sqlite3_open(dbName.c_str(), &db) != SQLITE_OK) {throw std::runtime_error("Can't open database: " + std::string(sqlite3_errmsg(db)));}}~Database() {sqlite3_close(db);}void executeQuery(const std::string& sql) {char* errMsg = nullptr;int rc = sqlite3_exec(db, sql.c_str(), callback, 0, &errMsg);if (rc != SQLITE_OK) {std::string error = "SQL error: " + std::string(errMsg);sqlite3_free(errMsg);throw std::runtime_error(error);}}void insertEmployee(const std::string& name, int id) {std::string sql = "INSERT INTO employees (name, id) VALUES ('" + name + "', " + std::to_string(id) + ");";executeQuery(sql);}void recordAttendance(int employeeId, const std::string& timestamp) {std::string sql = "INSERT INTO attendance (employee_id, timestamp) VALUES (" + std::to_string(employeeId) + ", '" + timestamp + "');";executeQuery(sql);}
};

代码说明:

  1. Database类封装了SQLite数据库的基本操作。
  2. 构造函数打开数据库连接,析构函数关闭连接。
  3. executeQuery方法执行SQL查询,使用回调函数处理结果。
  4. insertEmployee方法插入新员工记录。
  5. recordAttendance方法记录考勤信息。

3.4 Qt界面实现

以下是使用Qt实现主界面的代码示例:

#include <QMainWindow>
#include <QPushButton>
#include <QVBoxLayout>
#include <QMessageBox>class MainWindow : public QMainWindow {Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr) : QMainWindow(parent) {setWindowTitle("人脸识别考勤系统");QWidget *centralWidget = new QWidget(this);QVBoxLayout *layout = new QVBoxLayout(centralWidget);QPushButton *btnAttendance = new QPushButton("考勤签到", this);QPushButton *btnManage = new QPushButton("员工管理", this);QPushButton *btnReport = new QPushButton("考勤报表", this);layout->addWidget(btnAttendance);layout->addWidget(btnManage);layout->addWidget(btnReport);setCentralWidget(centralWidget);connect(btnAttendance, &QPushButton::clicked, this, &MainWindow::onAttendanceClicked);connect(btnManage, &QPushButton::clicked, this, &MainWindow::onManageClicked);connect(btnReport, &QPushButton::clicked, this, &MainWindow::onReportClicked);}
private slots:void onAttendanceClicked() {// 打开考勤签到界面QMessageBox::information(this, "考勤签到", "正在打开摄像头进行人脸识别...");// 这里可以调用人脸识别和考勤记录的相关函数}void onManageClicked() {// 打开员工管理界面QMessageBox::information(this, "员工管理", "正在打开员工管理界面...");// 这里可以实现一个新的对话框或窗口来管理员工信息}void onReportClicked() {// 生成考勤报表QMessageBox::information(this, "考勤报表", "正在生成考勤报表...");// 这里可以实现报表生成和显示的功能}
};// 主函数
int main(int argc, char *argv[]) {QApplication app(argc, argv);MainWindow mainWindow;mainWindow.show();return app.exec();
}

代码说明:

  1. MainWindow类继承自QMainWindow,实现了主界面的布局和功能。
  2. 构造函数中创建了三个按钮:考勤签到、员工管理和考勤报表。
  3. 使用QVBoxLayout垂直布局来排列按钮。
  4. 通过connect函数将按钮的点击事件与相应的槽函数连接。
  5. 三个槽函数onAttendanceClickedonManageClickedonReportClicked分别处理不同按钮的点击事件。
  6. 主函数创建并显示主窗口,启动Qt事件循环。

3.5 STM32与Qt通信

以下是STM32与Qt程序通过串口通信的示例代码:

// STM32端代码(使用HAL库)
#include "stm32f4xx_hal.h"UART_HandleTypeDef huart2;void UART_Init(void) {huart2.Instance = USART2;huart2.Init.BaudRate = 115200;huart2.Init.WordLength = UART_WORDLENGTH_8B;huart2.Init.StopBits = UART_STOPBITS_1;huart2.Init.Parity = UART_PARITY_NONE;huart2.Init.Mode = UART_MODE_TX_RX;huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;HAL_UART_Init(&huart2);
}void SendData(uint8_t* data, uint16_t size) {HAL_UART_Transmit(&huart2, data, size, HAL_MAX_DELAY);
}// Qt端代码
#include <QSerialPort>
#include <QSerialPortInfo>class SerialCommunication : public QObject {Q_OBJECTpublic:SerialCommunication(QObject *parent = nullptr) : QObject(parent) {serial = new QSerialPort(this);connect(serial, &QSerialPort::readyRead, this, &SerialCommunication::handleReadyRead);}bool openPort(const QString &portName) {serial->setPortName(portName);serial->setBaudRate(QSerialPort::Baud115200);return serial->open(QIODevice::ReadWrite);}void closePort() {if (serial->isOpen()) {serial->close();}}void sendData(const QByteArray &data) {if (serial->isOpen()) {serial->write(data);}}private slots:void handleReadyRead() {QByteArray data = serial->readAll();emit dataReceived(data);}signals:void dataReceived(const QByteArray &data);private:QSerialPort *serial;
};// 在主窗口中使用SerialCommunication类
class MainWindow : public QMainWindow {Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr) : QMainWindow(parent) {serialComm = new SerialCommunication(this);connect(serialComm, &SerialCommunication::dataReceived, this, &MainWindow::onDataReceived);// 初始化串口if (serialComm->openPort("COM3")) {  // 根据实际情况修改串口名qDebug() << "Serial port opened successfully";} else {qDebug() << "Failed to open serial port";}}private slots:void onDataReceived(const QByteArray &data) {// 处理接收到的数据qDebug() << "Received data:" << data;// 这里可以添加对接收数据的处理逻辑}void sendCommandToSTM32(const QString &command) {serialComm->sendData(command.toUtf8());}private:SerialCommunication *serialComm;
};

代码说明:

  1. SerialCommunication类封装了Qt串口通信的功能。
  2. openPort方法用于打开指定的串口。
  3. closePort方法用于关闭串口。
  4. sendData方法用于发送数据到STM32。
  5. handleReadyRead槽函数处理接收到的数据,并通过信号dataReceived发送出去。
  6. MainWindow类中,我们创建了SerialCommunication实例,并连接了数据接收的信号和槽。
  7. onDataReceived槽函数用于处理从STM32接收到的数据。
  8. sendCommandToSTM32方法用于向STM32发送命令。

3.6 人脸识别与考勤逻辑集成

以下是将人脸识别与考勤逻辑集成到Qt应用程序中的示例代码:

#include <QCamera>
#include <QCameraImageCapture>
#include <QTimer>
#include <QDateTime>
#include <opencv2/opencv.hpp>class AttendanceSystem : public QObject {Q_OBJECTpublic:AttendanceSystem(QObject *parent = nullptr) : QObject(parent) {faceDetector = new FaceDetector("haarcascade_frontalface_default.xml");faceRecognizer = new FaceRecognizer();database = new Database("attendance.db");camera = new QCamera(this);imageCapture = new QCameraImageCapture(camera);connect(imageCapture, &QCameraImageCapture::imageCaptured, this, &AttendanceSystem::processCapturedImage);// 每5秒捕获一次图像QTimer *timer = new QTimer(this);connect(timer, &QTimer::timeout, this, &AttendanceSystem::captureImage);timer->start(5000);}public slots:void startAttendance() {camera->start();}void stopAttendance() {camera->stop();}private slots:void captureImage() {imageCapture->capture();}void processCapturedImage(int id, const QImage &preview) {cv::Mat frame = QImageToMat(preview);std::vector<cv::Rect> faces = faceDetector->detectFaces(frame);for (const auto& face : faces) {cv::Mat faceROI = frame(face);int label;double confidence;faceRecognizer->predict(faceROI, label, confidence);if (confidence < 80.0) { // 假设置信度阈值为80recordAttendance(label);emit attendanceRecorded(label);}}}void recordAttendance(int employeeId) {QDateTime currentTime = QDateTime::currentDateTime();QString timestamp = currentTime.toString("yyyy-MM-dd hh:mm:ss");database->recordAttendance(employeeId, timestamp.toStdString());}private:FaceDetector *faceDetector;FaceRecognizer *faceRecognizer;Database *database;QCamera *camera;QCameraImageCapture *imageCapture;cv::Mat QImageToMat(const QImage &image) {cv::Mat mat;switch (image.format()) {case QImage::Format_RGB888:mat = cv::Mat(image.height(), image.width(), CV_8UC3, (void*)image.constBits(), image.bytesPerLine());cv::cvtColor(mat, mat, cv::COLOR_RGB2BGR);break;case QImage::Format_ARGB32_Premultiplied:mat = cv::Mat(image.height(), image.width(), CV_8UC4, (void*)image.constBits(), image.bytesPerLine());cv::cvtColor(mat, mat, cv::COLOR_RGBA2BGR);break;default:break;}return mat;}signals:void attendanceRecorded(int employeeId);
};

代码说明:

  1. AttendanceSystem 类集成了整个考勤系统的核心功能,包括摄像头控制、图像处理、人脸识别和考勤记录。

  2. 构造函数中:

    • 初始化 FaceDetectorFaceRecognizer 和 Database 对象。
    • 设置 QCamera 和 QCameraImageCapture 用于图像捕获。
    • 创建一个定时器,每5秒触发一次图像捕获。
  3. startAttendance() 和 stopAttendance() 方法用于启动和停止考勤过程。

  4. captureImage() 槽函数被定时器触发,用于捕获摄像头图像。

  5. processCapturedImage() 是核心处理函数:

    • 将 QImage 转换为 OpenCV 的 Mat 格式。
    • 使用 FaceDetector 检测人脸。
    • 对每个检测到的人脸进行识别。
    • 如果识别置信度高于阈值,则记录考勤。
  6. recordAttendance() 方法将考勤记录保存到数据库中,包括员工ID和时间戳。

  7. QImageToMat() 是一个辅助函数,用于将 Qt 的 QImage 转换为 OpenCV 的 Mat 格式。

  8. 类中定义了 attendanceRecorded 信号,当成功记录考勤时发出,可用于更新UI或通知其他组件。

  9. 整个系统通过定时捕获图像、检测人脸、识别身份、记录考勤的流程,实现了自动化的考勤功能。

  10. 该设计允许系统在后台持续运行,不需要人工干预即可完成考勤过程。

  11. 通过调整人脸识别的置信度阈值(此处设为80.0),可以平衡系统的准确性和灵敏度。

  12. 系统集成了数据库操作,确保考勤记录能够被永久保存和后续查询。

4. 项目总结

4.1 主要成果

  1. 成功实现了基于STM32和Qt的全栈人脸识别考勤系统。
  2. 集成了实时人脸检测和识别功能,提高了考勤效率。
  3. 开发了友好的用户界面,方便管理员操作和数据查询。
  4. 实现了考勤数据的自动化记录和统计分析功能。

4.2 技术亮点

  1. 采用OpenCV进行图像处理和人脸识别,提高了识别的准确性。
  2. 使用Qt框架开发跨平台桌面应用,提升了用户体验。
  3. 集成SQLite数据库,实现了高效的数据管理和查询。
  4. STM32与Qt的串口通信实现,使硬件控制更加灵活。

 

 

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据结构 day3

目录 思维导图&#xff1a; 学习内容&#xff1a; 1. 顺序表 1.1 概念 1.2 有关顺序表的操作 1.2.1 创建顺序表 1.2.2 顺序表判空和判断满 1.2.3 向顺序表中添加元素 1.2.4 遍历顺序表 1.2.5 顺序表按位置进行插入元素 1.2.6 顺序表任意位置删除元素 1.2.7 按值进…

Xcode 16 beta3 真机调试找不到 Apple Watch 的尝试解决

很多小伙伴们想用 Xcode 在 Apple Watch 真机上调试运行 App 时却发现&#xff1a;在 Xcode 设备管理器中压根找不到对应的 Apple Watch 设备。 大家是否已将 Apple Watch 和 Mac 都重启一万多遍了&#xff0c;还是束手无策。 Apple Watch not showing in XCodeApple Watch wo…

PHP手边酒店多商户版平台小程序系统源码

&#x1f3e8;【旅行新宠】手边酒店多商户版小程序&#xff0c;一键解锁住宿新体验&#xff01;&#x1f6cc; &#x1f308;【开篇&#xff1a;旅行新伴侣&#xff0c;尽在掌握】&#x1f308; 还在为旅行中的住宿选择而纠结吗&#xff1f;是时候告别繁琐的搜索和比价过程&a…

电脑屏幕录制怎么弄?分享3个简单的电脑录屏方法

在信息爆炸的时代&#xff0c;屏幕上的每一个画面都可能成为我们生活中不可或缺的记忆。作为一名年轻男性&#xff0c;我对于录屏软件的需求可以说是既挑剔又实际。今天&#xff0c;我就为大家分享一下我近期体验的三款录屏软件&#xff1a;福昕录屏大师、转转大师录屏大师和OB…

TikTok账号矩阵运营怎么做?

这几年&#xff0c;聊到出海避不过海外抖音&#xff0c;也就是TikTok&#xff0c;聊到TikTok电商直播就离不开账号矩阵&#xff1b; 在TikTok上&#xff0c;矩阵养号已经成为了出海电商人的流行策略&#xff0c;归根结底还是因为矩阵养号可以用最小的力&#xff0c;获得更大的…

FastAPI 学习之路(五十)WebSockets(六)聊天室完善

我们这次只是对于之前的功能做下优化&#xff0c;顺便利用下之前的操作数据的接口&#xff0c;使用下数据库的练习。 在聊天里会有一个上线的概念。上线要通知大家&#xff0c;下线也要通知大家谁离开了&#xff0c;基于此功能我们完善下代码。 首先&#xff0c;我们的登录用…

初识langchain[1]:Langchain实战教学,利用qwen2.1与GLM-4大模型构建智能解决方案[含Agent、tavily面向AI搜索]

初识langchain[1]&#xff1a;Langchain实战教学&#xff0c;利用qwen2.1与GLM-4大模型构建智能解决方案 1.大模型基础知识 大模型三大重点&#xff1a;算力、数据、算法&#xff0c;ReAct &#xff08;reason推理act行动&#xff09;–思维链 Langchain会把上述流程串起来&a…

[Maven] 打包编译本地Jar包报错的几种解决办法

目录 方式1&#xff1a;通过scope指定 方式2&#xff1a;通过新建lib 方式3&#xff1a;通过build节点打包依赖​​​​​​​ 方式4&#xff1a;安装Jar包到本地 方式5&#xff1a;发布到远程私有仓库 方式6&#xff1a;删除_remote.repositories 方式7&#xff1a;打包…

vscode+wsl2+anaconda环境的配置与使用

目录 下载anaconda Anaconda使用参考 vscodeubuntuanaconda 先用vscode连接本地ubuntu。 如果没有安装wsl2与ubuntu&#xff0c;可点击下面的链接。 问题&#xff1a;wsl install 无法解析服务器 成功记录&#xff1a; 在vscode终端用ubuntu安装anaconda。 创建pytho…

[word] word表格跨页断开实现教程 #职场发展#媒体

word表格跨页断开实现教程 选中整个word表格 单击鼠标右键&#xff0c;选择“表格属性”选项 切换至“行”标签&#xff0c;找到“允许跨页断行”选项 勾选上“允许跨页断行”&#xff0c;单击“确定”按钮&#xff0c;完成&#xff01; word表格跨页断开实现教程的下载地址&a…

微信小程序密码 显示隐藏 真机兼容问题

之前使用type来控制&#xff0c;发现不行&#xff0c;修改为password属性即可 <van-fieldright-icon"{{passwordType password? closed-eye:eye-o}}"model:value"{{ password }}"password"{{passwordType password ? true: false}}"borde…

一款IM即时通讯聊天系统源码,包含app和后台源码

一款IM即时通讯聊天系统源码 聊天APP 附APP&#xff0c;后端是基于spring boot开发的。 这是一款独立服务器部署的即时通讯解决方案&#xff0c;可以帮助你快速拥有一套自己的移动社交、 企业办公、多功能业务产品。可以 独立部署&#xff01;加密通道&#xff01;牢牢掌握通…

水域救援装备的详细简介_鼎跃安全

水域救援行动需要救援人员配备全面、专业的装备&#xff0c;以应对各种复杂的水域环境和救援任务。水域救援套装应运而生&#xff0c;它集合了水域救援所需的各类关键装备&#xff0c;为救援人员提供全方位的保护和辅助&#xff0c;确保数援行动的高效与安全。 水域救援头盔&am…

基于语音识别的会议记录系统

文章目录 核心功能页面展示使用技术方案功能结构设计数据库表展示 核心功能页面展示 视频展示功能 1.创建会议 在开始会议之前需要管理员先创建一个会议&#xff0c;为了能够快速开始会议&#xff0c;仅需填写会议的名称、会议举办小组、会议背景等简要会议信息即可成功创建。…

CTF-Web习题:[HFCTF2021]Unsetme

题目链接&#xff1a;[HFCTF2021]Unsetme 解题思路 打开靶场发现是一段PHP源码 做一下代码审阅&#xff1a; <?php// Kickstart the framework $f3require(lib/base.php);//引入f3框架源码$f3->set(DEBUG,1);//f3对象设置DEBUG属性 if ((float)PCRE_VERSION<8.0)…

中科微电子ATGM336H GPS定位模块STM32应用

文章目录 前言1. 中科微电子ATGM336H的使用1.1 ATGM336H引脚说明1.2 数据帧介绍1.3 经纬度介绍1.4 ATGM336H的启动方式 2 数据处理前置C语言知识2.1 strstr函数2.2 memset函数2.3 memcpy函数2.4strtod函数 3. 开始移植3.1 usart初始化程序3.2 串口中断接收函数3.4 数据帧的解析…

Leetcode算法题(移除链表中的元素)

题目如下&#xff1a; 思路1&#xff1a;创建一个新的带头链表 &#xff08;newhead&#xff09;&#xff0c;遍历头结点对应的值分别于x进行比较&#xff0c;将不等于x的节点尾插到新的带头链表中&#xff0c;返回新的带头链表的下一个节点。 代码如下&#xff1a; typedef …

路由数据获取及封装方法

数据库设计 自联表 定义tree字段 public class LabelValue{public int label { get; set; }public string? value { get; set; }public List<LabelValue> children { get; set; }}获取路由方法 public Response<object> getMenuList() {Response<object>…

RK3568笔记四十:设备树

若该文为原创文章&#xff0c;转载请注明原文出处。 一、介绍 设备树 (Device Tree) 的作用就是描述一个硬件平台的硬件资源&#xff0c;一般描述那些不能动态探测到的设备&#xff0c;可以被动态探测到的设备是不需要描述。 设备树可以被 bootloader(uboot) 传递到内核&#x…

反爬虫策略中的IP地址轮换如何实现?挑战与对策

当今互联网时代&#xff0c;各类网站、网络平台背后隐藏着大量数据&#xff0c;广告数据收集、市场数据收集都需要依托爬虫技术&#xff0c;但很多网站通过反爬虫技术限制或屏蔽爬虫的访问&#xff0c;这给数据收集带来不小的挑战。 为了规避这些反爬虫策略&#xff0c;开发人…