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);}}
};
代码说明:
FaceDetector
类封装了人脸检测功能。- 构造函数加载Haar级联分类器文件。
detectFaces
方法接收一帧图像,返回检测到的人脸矩形区域。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);}
};
代码说明:
FaceRecognizer
类封装了LBPH人脸识别器的功能。- 构造函数创建LBPH人脸识别器实例。
train
方法用于训练模型。predict
方法进行人脸识别,返回预测的标签和置信度。saveModel
和loadModel
方法用于保存和加载训练好的模型。
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);}
};
代码说明:
Database
类封装了SQLite数据库的基本操作。- 构造函数打开数据库连接,析构函数关闭连接。
executeQuery
方法执行SQL查询,使用回调函数处理结果。insertEmployee
方法插入新员工记录。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();
}
代码说明:
MainWindow
类继承自QMainWindow
,实现了主界面的布局和功能。- 构造函数中创建了三个按钮:考勤签到、员工管理和考勤报表。
- 使用
QVBoxLayout
垂直布局来排列按钮。 - 通过
connect
函数将按钮的点击事件与相应的槽函数连接。 - 三个槽函数
onAttendanceClicked
、onManageClicked
和onReportClicked
分别处理不同按钮的点击事件。 - 主函数创建并显示主窗口,启动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;
};
代码说明:
SerialCommunication
类封装了Qt串口通信的功能。openPort
方法用于打开指定的串口。closePort
方法用于关闭串口。sendData
方法用于发送数据到STM32。handleReadyRead
槽函数处理接收到的数据,并通过信号dataReceived
发送出去。- 在
MainWindow
类中,我们创建了SerialCommunication
实例,并连接了数据接收的信号和槽。 onDataReceived
槽函数用于处理从STM32接收到的数据。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);
};
代码说明:
-
AttendanceSystem
类集成了整个考勤系统的核心功能,包括摄像头控制、图像处理、人脸识别和考勤记录。 -
构造函数中:
- 初始化
FaceDetector
、FaceRecognizer
和Database
对象。 - 设置 QCamera 和 QCameraImageCapture 用于图像捕获。
- 创建一个定时器,每5秒触发一次图像捕获。
- 初始化
-
startAttendance()
和stopAttendance()
方法用于启动和停止考勤过程。 -
captureImage()
槽函数被定时器触发,用于捕获摄像头图像。 -
processCapturedImage()
是核心处理函数:- 将 QImage 转换为 OpenCV 的 Mat 格式。
- 使用 FaceDetector 检测人脸。
- 对每个检测到的人脸进行识别。
- 如果识别置信度高于阈值,则记录考勤。
-
recordAttendance()
方法将考勤记录保存到数据库中,包括员工ID和时间戳。 -
QImageToMat()
是一个辅助函数,用于将 Qt 的 QImage 转换为 OpenCV 的 Mat 格式。 -
类中定义了
attendanceRecorded
信号,当成功记录考勤时发出,可用于更新UI或通知其他组件。 -
整个系统通过定时捕获图像、检测人脸、识别身份、记录考勤的流程,实现了自动化的考勤功能。
-
该设计允许系统在后台持续运行,不需要人工干预即可完成考勤过程。
-
通过调整人脸识别的置信度阈值(此处设为80.0),可以平衡系统的准确性和灵敏度。
-
系统集成了数据库操作,确保考勤记录能够被永久保存和后续查询。
4. 项目总结
4.1 主要成果
- 成功实现了基于STM32和Qt的全栈人脸识别考勤系统。
- 集成了实时人脸检测和识别功能,提高了考勤效率。
- 开发了友好的用户界面,方便管理员操作和数据查询。
- 实现了考勤数据的自动化记录和统计分析功能。
4.2 技术亮点
- 采用OpenCV进行图像处理和人脸识别,提高了识别的准确性。
- 使用Qt框架开发跨平台桌面应用,提升了用户体验。
- 集成SQLite数据库,实现了高效的数据管理和查询。
- STM32与Qt的串口通信实现,使硬件控制更加灵活。