传统考勤方式存在诸多痛点:代打卡、排队耗时、数据统计繁琐等问题长期困扰着企业HR和学校管理者。我在为某高校实验室开发管理系统时,发现他们仍在使用纸质签到表,每月统计考勤要耗费管理员整整两天时间。这促使我开发了这套基于Python的人脸识别考勤系统,经过三个月的迭代优化,最终实现了98.7%的识别准确率。
系统核心技术栈采用:
选择Django框架主要基于其完善的Admin管理系统和ORM支持。实测表明,使用Django开发管理类系统相比Flask能节省约40%的后台代码量。人脸检测模块对比了多种方案:
| 方案 | 准确率 | 速度(fps) | 硬件需求 |
|---|---|---|---|
| OpenCV Haar | 82% | 25 | 低 |
| Dlib HOG | 89% | 18 | 中 |
| MTCNN | 95% | 12 | 高 |
| 本系统(改进Dlib) | 98.7% | 15 | 中 |
最终采用Dlib的HOG特征检测器配合自定义的LBP特征增强,在普通i5处理器上即可达到实时识别要求。
系统采用经典的三层架构:
code复制[前端Vue] ←HTTP→ [Django REST API] ←ORM→ [MySQL]
↑
[人脸识别服务]
↑
[OpenCV/Dlib/Numpy]
特别设计了异步处理机制:当同时有多个签到请求时,系统会将人脸检测任务放入Celery任务队列,避免主线程阻塞。实测显示,这种设计使系统在50人并发签到时的响应时间保持在1.2秒以内。
python复制def preprocess_image(img):
# 灰度化 + 直方图均衡化
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
return clahe.apply(gray)
注意:CLAHE参数需根据摄像头质量调整,低光照环境下建议clipLimit=3.0
python复制detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor("shape_predictor_68.dat")
def get_landmarks(image):
faces = detector(image, 1)
if len(faces) == 0:
return None
return np.array([[p.x, p.y] for p in predictor(image, faces[0]).parts()])
python复制facerec = dlib.face_recognition_model_v1("dlib_face_recognition_resnet_model_v1.dat")
def get_face_descriptor(image, landmarks):
return facerec.compute_face_descriptor(image, landmarks)
考勤记录表设计考虑了高频写入特点:
sql复制CREATE TABLE `attendance` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`user_id` bigint(20) NOT NULL COMMENT '外键关联用户表',
`check_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`location` varchar(255) DEFAULT NULL COMMENT 'GPS坐标或WiFi定位',
`device_id` varchar(64) DEFAULT NULL COMMENT '签到设备标识',
`image_path` varchar(255) DEFAULT NULL COMMENT人脸截图存储路径',
PRIMARY KEY (`id`),
INDEX `idx_user_time` (`user_id`, `check_time`),
INDEX `idx_time` (`check_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
踩坑记录:最初未添加复合索引时,月度考勤统计查询耗时达8秒,优化后降至0.3秒
mermaid复制sequenceDiagram
前端->>后端: 发起视频流请求
后端->>OpenCV: 获取视频帧
OpenCV->>Dlib: 人脸检测
alt 检测到人脸
Dlib->>后端: 返回特征向量
后端->>数据库: 特征比对
数据库-->>后端: 返回比对结果
后端->>前端: 显示识别结果
else 未检测到
后端->>前端: 提示调整位置
end
实际开发中发现,直接传输视频流对服务器压力较大,最终改为前端每200ms截取一帧上传的方案。
采用双层缓存策略提高报表生成速度:
关键统计SQL示例:
sql复制SELECT
u.name,
COUNT(CASE WHEN DATE(a.check_time)=CURDATE() THEN 1 END) AS today,
SUM(CASE WHEN TIME(a.check_time)<'09:30:00' THEN 1 ELSE 0 END)/COUNT(*)*100 AS punctuality_rate
FROM
attendance a
JOIN
users u ON a.user_id=u.id
GROUP BY
u.id
Nginx关键配置项:
code复制location /api {
proxy_pass http://127.0.0.1:8000;
proxy_read_timeout 300s;
client_max_body_size 20M; # 允许大尺寸图片上传
}
location /media {
alias /var/www/media;
expires 30d; # 静态资源缓存
}
通过实验发现,将人脸检测和特征提取分离到不同进程可提升吞吐量:
python复制# 使用multiprocessing创建专用检测进程
detection_queue = Queue()
result_queue = Queue()
detector_process = Process(
target=face_detection_worker,
args=(detection_queue, result_queue)
)
detector_process.start()
实测数据对比:
| 模式 | QPS | 平均延迟 |
|---|---|---|
| 单线程 | 12 | 83ms |
| 多进程 | 38 | 26ms |
| 异步IO | 45 | 22ms |
现象:强逆光环境下识别率下降至60%
解决方案:
python复制cv2.createTonemapReinhard().process(img, img)
案例:某中学双胞胎学生互相代打卡
改进措施:
项目源码中已包含完整的Docker部署文件,通过docker-compose up即可一键启动所有服务。对于中小型企业,建议使用2核4G的云服务器配置,可支持200人同时签到。