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);
}
}
};
代码说明:
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_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();
}
代码说明:
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_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;
};
代码说明:
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_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);
};
代码说明:
-
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的串口通信实现,使硬件控制更加灵活。
原文地址:https://blog.csdn.net/qq_40431685/article/details/140519451
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!