当前位置: 首页 > news >正文

从头开始开发基于虹软SDK的人脸识别考勤系统(python+RTSP开源)(二)

今天咱们继续昨天的话题,今天的重点是看思路和代码了。废话不多说,直接上干货。

先说一句,为了省事,直接一个文件完成所有功能,可能在代码可读性上差一些,比较眼花缭乱哈哈。整个文件含空行代码共1931行;咱们一点点说。

先说一下配置环境问题,我使用的是conda,配置dev为phthon 3.9

一、环境问题:

首先是python库有哪些,见代码

# -*- coding: utf-8 -*-
import logging
import sys
import os
import cv2
import sqlite3
import numpy as np
import pyttsx3
import shutil
import zipfile
from datetime import datetime
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QTimer, QDate, QPoint, QMutex,QPropertyAnimation, QEasingCurve
from PyQt5.QtGui import (QImage, QPixmap, QFont, QIcon, QPainter, QPen,
                         QColor, QLinearGradient, QCursor, QBrush)
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QLabel, QPushButton,
                             QTableWidget, QTableWidgetItem, QFileDialog, QMessageBox,
                             QVBoxLayout, QHBoxLayout, QFormLayout, QInputDialog, QDialog,
                             QDialogButtonBox, QLineEdit, QComboBox, QDateEdit, QTabWidget,
                             QSystemTrayIcon, QMenu, QAction, QSpinBox, QCheckBox, QStyleFactory,QSizePolicy,QGraphicsOpacityEffect )
import ctypes
from ctypes import c_void_p, c_int, c_float, c_char_p, Structure, POINTER
from ctypes import cdll
import lunardate
import threading
import pandas as pd
import requests
from bs4 import BeautifulSoup

 requirements.txt 文件内容,不用考虑版本号,这些库在安装的时候也是问题一堆的出。

altgraph==0.17.4
beautifulsoup4==4.13.3
certifi==2025.1.31
charset-normalizer==3.4.1
chinese-calendar==1.8.0
click==8.1.8
colorama==0.4.6
comtypes==1.4.10
dlib==19.24.2
greenlet==3.1.1
holidays==0.67
idna==3.10
importlib_metadata==8.6.1
lunardate==0.2.2
ntplib==0.4.0
Nuitka==2.6.7
numpy==1.23.5
opencv-python==4.5.5.64
ordered-set==4.1.0
packaging==24.2
pandas==2.2.3
pefile==2023.2.7
pillow==11.1.0
pyinstaller==6.12.0
pyinstaller-hooks-contrib==2025.1
pypiwin32==223
PyQt5==5.15.11
PyQt5-Qt5==5.15.2
PyQt5_sip==12.17.0
python-dateutil==2.8.2
python-dotenv==0.21.1
pyttsx3==2.90
pytz==2025.1
pywin32==308
pywin32-ctypes==0.2.3
PyYAML==6.0
requests==2.32.3
sip==6.10.0
six==1.17.0
soupsieve==2.6
SQLAlchemy==1.4.46
tomli==2.2.1
typing_extensions==4.12.2
tzdata==2025.1
urllib3==2.3.0
zipp==3.21.0
zstandard==0.23.0

其他依赖的内容:

CMAKE必须;还有微软的开发包,忘记具体是啥了,反正我机器上又visual studio。你pip install -r的时候就知道会出一堆错误 ,基本就是dlib的问题。对照提示解决就是,实在不懂,直接复制错误扔给AI回答。

二、开发工具

简单说一下工具哈

代码中我大部分都加了注释,实在嫌麻烦的可以用visual studio code 安装codeX,选择代码加注释给你解释就好了,其实CODE这个插件特别多,很好用!以前我用的是sublime text,后来就完全被code替代了。

codeX让我卸载了?可能是嫌他介入的太多了,用TONGYI灵码也很好。

三、功能实现代码

# 配置日志记录
logging.basicConfig(filename='app.log', level=logging.INFO,
                    format='%(asctime)s - %(levelname)s - %(message)s')

关键点:虹软SDK的常量和结构定义

# 定义虹软SDK相关常量
ASF_FACE_DETECT = 0x00000001
ASF_FACERECOGNITION = 0x00000004
ASF_AGE = 0x00000008
ASF_GENDER = 0x00000010
ASF_FACE3DANGLE = 0x00000020
ASF_LIVENESS = 0x00000080
ASF_IR_LIVENESS = 0x00000400

ASF_DETECT_MODE_VIDEO = 0x00000000
ASF_DETECT_MODE_IMAGE = 0xFFFFFFFF
ASF_OP_0_ONLY = 0x1

ASF_PAF_RGB24_B8G8R8 = 0x201


# 虹软SDK结构定义
class ASF_VERSION(Structure):
    _fields_ = [
        ("Version", c_char_p),
        ("BuildDate", c_char_p),
        ("CopyRight", c_char_p)
    ]


class ASF_ActiveFileInfo(Structure):
    _fields_ = [
        ("startTime", c_char_p),
        ("endTime", c_char_p),
        ("activeKey", c_char_p),
        ("platform", c_char_p),
        ("sdkType", c_char_p),
        ("appId", c_char_p),
        ("sdkKey", c_char_p),
        ("sdkVersion", c_char_p),
        ("fileVersion", c_char_p)
    ]


class MRECT(Structure):
    _fields_ = [
        ("left", c_int),
        ("top", c_int),
        ("right", c_int),
        ("bottom", c_int)
    ]


class ASF_SingleFaceInfo(Structure):
    _fields_ = [
        ("faceRect", MRECT),
        ("faceOrient", c_int)
    ]


class ASF_MultiFaceInfo(Structure):
    _fields_ = [
        ("faceRect", POINTER(MRECT)),
        ("faceOrient", POINTER(c_int)),
        ("faceNum", c_int),
        ("faceID", POINTER(c_int))
    ]


class ASF_FaceFeature(Structure):
    _fields_ = [
        ("feature", c_void_p),
        ("featureSize", c_int)
    ]


class ASVLOFFSCREEN(Structure):
    _fields_ = [
        ("u32PixelArrayFormat", c_int),
        ("i32Width", c_int),
        ("i32Height", c_int),
        ("ppu8Plane", POINTER(POINTER(c_int))),
        ("pi32Pitch", POINTER(c_int))
    ]

系统配置,换上你们自己的SDK,目录你们自己随便建立,./Arcsdk/libarcsoft_face_engine.dll,这个你放在哪里就改到哪里。

# 系统配置
class AppConfig:
    def __init__(self):
        self.db_name = "attendance.db"
        self.backup_dir = "backups"
        self.face_img_dir = "static/face_images"
        self.camera_img_dir = "static/camera_images"
        self.recognition_threshold = 0.7
        self.check_interval = 2000

        os.makedirs(self.backup_dir, exist_ok=True)
        os.makedirs(self.face_img_dir, exist_ok=True)
        os.makedirs(self.camera_img_dir, exist_ok=True)

        self.face_algorithm = 'arcsoft'
        self.arcsoft_appid = b"换上你自己的APPID"
        self.arcsoft_sdkkey = b"换上你自己的SDKKEY"
        self.arcsoft_lib_path = os.path.abspath("./Arcsdk/libarcsoft_face_engine.dll")
        # print(f"虹软SDK库文件路径: {self.arcsoft_lib_path}")  # 打印库文件路径

数据库部分:

# 数据库服务
class DatabaseService:
    def __init__(self):
        # 初始化锁对象
        self.lock = threading.Lock()
        try:
            self.conn = sqlite3.connect(config.db_name)
            with self.conn:
                self._initialize_db()
        except sqlite3.Error as e:
            print(f"数据库连接失败: {e}")
            raise

    def _initialize_db(self):
        cursor = self.conn.cursor()
        cursor.execute('''
            CREATE TABLE IF NOT EXISTS staff (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                name TEXT NOT NULL,
                department TEXT DEFAULT '未分配',
                photo_path TEXT NOT NULL,
                face_encoding BLOB NOT NULL,
                created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
                is_active BOOLEAN DEFAULT 1
            )''')
        cursor.execute('''
            CREATE TABLE IF NOT EXISTS attendance (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                staff_id INTEGER NOT NULL,
                check_time DATETIME NOT NULL,
                date TEXT NOT NULL, 
                check_type TEXT CHECK(check_type IN ('morning', 'noon', 'night')),
                is_holiday BOOLEAN,
                camera_id INTEGER,
                FOREIGN KEY(staff_id) REFERENCES staff(id)
            )''')
        cursor.execute('''
            CREATE TABLE IF NOT EXISTS camera_config (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                camera_type TEXT CHECK(camera_type IN ('usb', 'rtsp')),
                rtsp_url TEXT,
                is_enabled BOOLEAN DEFAULT 0,
                is_connected BOOLEAN DEFAULT 0
            )''')
        self.conn.commit()

员工管理

以添加员工最为重要,需要导入照片后提取人脸特征码存储。


    def add_staff(self, name, department, photo_path, encoding):
        try:
            cursor = self.conn.cursor()
            cursor.execute('''
                INSERT INTO staff (name, department, photo_path, face_encoding)
                VALUES (?,?,?,?)''',
                           (name, department, photo_path, encoding if isinstance(encoding, bytes) else encoding.tobytes()))
            self.conn.commit()
            staff_id = cursor.lastrowid
            logging.info(f"成功添加员工,ID: {staff_id}, 姓名: {name}")
            return cursor.lastrowid
        except sqlite3.Error as e:
            self.conn.rollback()
            logging.error(f"添加员工失败: {e}")
            print(f"添加员工失败: {e}")
            raise

    def get_staff(self, staff_id=None):
        cursor = self.conn.cursor()
        if staff_id:
            cursor.execute('SELECT * FROM staff WHERE id=? AND is_active=1', (staff_id,))
            return cursor.fetchone()
        cursor.execute('SELECT * FROM staff WHERE is_active=1')
        return cursor.fetchall()

    def delete_staff(self, staff_id):
        try:
            cursor = self.conn.cursor()
            cursor.execute('UPDATE staff SET is_active=0 WHERE id=?', (staff_id,))
            self.conn.commit()
        except sqlite3.Error as e:
            print(f"删除员工失败: {e}")
            raise

还写了个数据备份的功能,简单的很,压缩存储文件

    def create_backup(self, backup_path):
        try:
            with zipfile.ZipFile(backup_path, 'w') as zipf:
                zipf.write(config.db_name)
                for root, _, files in os.walk(config.face_img_dir):
                    for file in files:
                        zipf.write(os.path.join(root, file))
        except Exception as e:
            print(f"备份数据失败: {e}")
            raise

    def close(self):
        if self.conn:
            self.conn.close()

今天先这些吧,时间有点晚了,准备撤退回家了。

相关文章:

  • 【HarmonyOS Next】鸿蒙应用加载SVG文件显示图标
  • ArcGIS Pro字段编号相关代码
  • Kafka常用指令(详细)
  • 2025华为OD机试真题最新题库 (B+C+D+E卷) + 在线OJ在线刷题使用说明(C++、Java、Python合集)(正在更新E卷,目前已收录581道)
  • 【时序图】1.StarUML绿化
  • Scala编程_实现Rational的基本操作
  • 远程监控项目描述以及总体框架
  • C# 泛型中的协变、抗变和裂变:概念与应用
  • SSM框架
  • NLP常见任务专题介绍(1)-关系抽取(Relation Extraction, RE)任务训练模板
  • SSH可以连接成功,但VSCode连接不成功的问题
  • 【GPT入门】第6课 openai接口介绍与参数说明
  • 【09】单片机编程核心技巧:变量赋值,从定义到存储的底层逻辑
  • blender学习25.3.11
  • visual studio 2022最常用的快捷键
  • 小程序实现存储用户注册信息功能 前后端+数据库联调
  • 《 C++ 点滴漫谈: 三十 》高手写 C++,参数这样传才高效!你真的用对了吗?
  • 分而治之:用于 RGB-T 显著目标检测的 Confluent Triple-Flow 网络
  • Elasticsearch Java API Client [8.17] 使用
  • bug小记
  • 国家统计局向多省份反馈统计督察意见
  • 体坛联播|博洛尼亚时隔51年再夺意杯,皇马逆转马洛卡
  • 哪种“网红减肥法”比较靠谱?医学专家和运动专家共同解答
  • 公元1058年:柳永词为什么时好时坏?
  • 广东省中医院脾胃病科大科主任张北平病逝,年仅52岁
  • 刘国中:持续加强护士队伍建设,更好保障人民身体健康