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

news2024/9/21 15:42:14

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_OBJECT

public:
    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_OBJECT

public:
    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_OBJECT

public:
    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_OBJECT

public:
    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) { // 假设置信度阈值为80
                recordAttendance(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.coloradmin.cn/o/1934759.html

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

相关文章

高性能、安全、低碳绿色的趋势下,锐捷网络发布三擎云办公解决方案 3.0

桌面虚拟化作为云时代的主流和热门技术&#xff0c;已经取得了广泛应用。随着生成式 AI 爆炸式发展&#xff0c;CSDN 看到&#xff0c;人工智能正在引发计算、开发、交互三大范式的全面升级&#xff0c;技术开发或将迎来一次全新的科技变革周期&#xff0c;因此 VDI 云桌面随之…

亚马逊自发货erp,虚拟自动化发货功能以及1688订单采购

亚马逊自发货erp自动化功能&#xff0c;自动同步订单&#xff0c;1688订单同步。 大家好&#xff0c;今天分享一个非常实用并且节省时间的功能&#xff1a;自动化发货以及1688同步订单。 首先来看下自动化发货功能怎么操作。 →要在商品信息里面添加商品信息&#xff0c;上传…

C#语法基础详解(万字总结)

文章目录 **参考书籍&#xff1a;C#7.0 核心技术指南**类型类字段解构器对象初始化器属性表达式属性(只读属性才可以)自动属性属性初始化器 索引器静态构造器nameof运算符 继承类型转换和引用转换as运算符is运算符is与模式变量 虚函数成员抽象类和抽象成员new和重写base关键字构…

JavaDS —— 二叉树

树的基本概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看 起来像一棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下的。 树形结构中&#xff0c;子树之间不能有…

网易滑块逆向

版本 2.27.2 混淆难度挺大 没反混淆 直接硬着直接干 参数还是那些 滑块&#xff08;其他类型也一样&#xff09;成功率 100%

= null 和 is null;SQL中关于NULL处理的4个陷阱;三值逻辑

一、概述 1、NULL参与的所有的比较和算术运算符(>,,<,<>,<,>,,-,*,/) 结果为unknown&#xff1b; 2、unknown的逻辑运算(AND、OR、NOT&#xff09;遵循三值运算的真值表&#xff1b; 3、如果运算结果直接返回用户&#xff0c;使用NULL来标识unknown 4、如…

CSS技巧专栏:一日一例 8 - 纯CSS利用mask属性实现按钮边框对称包围特效

CSS技巧专栏:一日一例 8 - 纯CSS利用mask属性实现按钮边框对称包围特效 上篇作业解题 在前一篇文章的最后,给各位看官留了一个作业,如上图所示。本篇文章,我们来公布一下它的源码。 主要实现的思路 四个渐变色的线段,沿着四个方向的依次运动,(运动在加载前执行)使用 …

物联网实训室的核心功能有哪些?

随着物联网技术的迅猛发展和广泛应用&#xff0c;唯众凭借其深厚的技术积累和丰富的行业经验&#xff0c;为职业院校提供了全面的物联网实训室解决方案。这些实训室不仅为学生提供了真实、实用、创新的实践环境&#xff0c;还促进了产学研用的深度融合&#xff0c;推动了物联网…

深度学习根据代码可视化模型结构图的方法

方法1. Netron Netron 是一个支持多种深度学习模型格式的可视化工具&#xff0c;可以将 PyTorch 模型转换为 ONNX 格式&#xff0c;然后使用 Netron 进行可视化。 安装 Netron&#xff1a; pip install netron使用示例&#xff1a; import torch.onnx# 定义模型 model EMA…

上海理工大学24计算机考研考情分析!初复试分值比55:45,复试逆袭人数不算多!

上海理工大学&#xff08;University of Shanghai for Science and Technology&#xff09;&#xff0c;位于上海市&#xff0c;是一所以工学为主&#xff0c;工学、理学、经济学、管理学、文学、法学、艺术学等多学科协调发展的应用研究型大学&#xff1b;是上海市属重点建设大…

秒懂C++之类与对象(中)

目录 一.流插入&#xff0c;流提取运算符 二.const成员函数 三.取地址重载 四.构造函数&#xff08;列表初始化&#xff09; 小测试&#xff1a; 五.全部代码 前排提醒&#xff1a;本文所参考代码仍是取用上篇文章关于日期类相关功能的实现~末尾有全部代码~ 一.流插入&a…

使用Redis的SETNX命令实现分布式锁

什么是分布式锁 分布式锁是一种用于在分布式系统中控制多个节点对共享资源进行访问的机制。在分布式系统中&#xff0c;由于多个节点可能同时访问和修改同一个资源&#xff0c;因此需要一种方法来确保在任意时刻只有一个节点能够对资源进行操作&#xff0c;以避免数据不一致或…

WPF/C#:实现导航功能

前言 在WPF中使用导航功能可以使用Frame控件&#xff0c;这是比较基础的一种方法。前几天分享了wpfui中NavigationView的基本用法&#xff0c;但是如果真正在项目中使用起来&#xff0c;基础的用法是无法满足的。今天通过wpfui中的mvvm例子来说明在wpfui中如何通过依赖注入与M…

STM32智能安防系统教程

目录 引言环境准备智能安防系统基础代码实现&#xff1a;实现智能安防系统 4.1 数据采集模块 4.2 数据处理与控制模块 4.3 通信与网络系统实现 4.4 用户界面与数据可视化应用场景&#xff1a;家庭与企业安防管理问题解决方案与优化收尾与总结 1. 引言 智能安防系统通过STM32…

解决npm install(‘proxy‘ config is set properly. See: ‘npm help config‘)失败问题

摘要 重装电脑系统后&#xff0c;使用npm install初始化项目依赖失败了&#xff0c;错误提示&#xff1a;‘proxy’ config is set properly…&#xff0c;具体的错误提示如下图所示&#xff1a; 解决方案 经过报错信息查询解决办法&#xff0c;最终找到了两个比较好的方案&a…

【Charles】-雷电模拟器-抓HTTPS包

写在前面 之前的文章我们写过如何通过Charles来抓取IOS手机上的HTTPS包以及遇到的坑。说一个场景&#xff0c;如果你的手机是IOS&#xff0c;但是团队提供的APP安装包是Android&#xff0c;这种情况下你还想抓包&#xff0c;怎么办&#xff1f; 不要慌&#xff0c;我们可以安装…

宝塔面板以www用户运行composer

方式一 执行命令时指定www用户 sudo -u www composer update方式二 在网站配置中的composer选项卡中选择配置运行

c# .net core中间件,生命周期

某些模块和处理程序具有存储在 Web.config 中的配置选项。但是在 ASP.NET Core 中&#xff0c;使用新配置模型取代了 Web.config。 HTTP 模块和处理程序如何工作 官网地址&#xff1a; 将 HTTP 处理程序和模块迁移到 ASP.NET Core 中间件 | Microsoft Learn 处理程序是&#xf…

大数据之路 读书笔记 Day7 实时技术 简介及流式技术架构

回顾&#xff1a; Day6 离线数据开发之数据开发平台Day5 数据同步遇到的问题与解决方案 1. 简介 阿里巴巴在流式数据处理方面采用了多种技术和框架&#xff0c;这些技术的特点包括&#xff1a; 高可伸缩性&#xff1a; 阿里巴巴使用Apache Flink进行大规模数据处理&#xff0c…

【已解决】Django连接MySQL启动报错Did you install mysqlclient?

在终端执行python manage.py makemigrations报错问题汇总 错误1&#xff1a;已安装mysqlclient&#xff0c;提示Did you install mysqlclient? 当你看到这样的错误信息&#xff0c;表明Django尝试加载MySQLdb模块但未找到&#xff0c;因为MySQLdb已被mysqlclient替代。 【解…