java/php/net/python人脸识别考勤系统【2026年毕设】
·
一、项目概述
1.1 系统背景
随着人工智能技术的快速发展,人脸识别技术在各个领域得到了广泛应用。传统的考勤方式(如打卡机、指纹识别、签到表等)存在代打卡、接触式卫生问题、效率低下等弊端。基于人脸识别的考勤系统能够有效解决这些问题,实现无接触、高效率、高准确率的考勤管理。
1.2 系统特点
-
多语言实现:提供Java、PHP、Python、.NET四种技术栈实现方案
-
高精度识别:基于深度学习人脸识别算法,识别准确率达99%以上
-
实时考勤:支持实时人脸检测与识别,自动记录考勤时间
-
多端适配:支持Web端、移动端、桌面端应用
-
数据可视化:考勤数据统计分析,图表展示
二、技术选型对比
| 技术栈 | 优势 | 适用场景 | 主要依赖 |
|---|---|---|---|
| Java | 稳定性高,适合大型企业级应用 | 企业级考勤系统 | Spring Boot, OpenCV, MySQL, MyBatis |
| PHP | 开发速度快,部署简单 | 中小型Web考勤系统 | Laravel/ThinkPHP, OpenCV, MySQL |
| Python | AI生态完善,算法集成方便 | 需要深度优化算法的系统 | Django/Flask, TensorFlow/PyTorch, dlib, face_recognition |
| .NET | Windows生态集成好 | 企业内部Windows环境 | ASP.NET Core, OpenCVSharp, SQL Server |
三、系统功能模块
3.1 用户端功能
├── 人脸注册
│ ├── 拍照录入
│ ├── 图片上传
│ └── 活体检测
├── 日常考勤
│ ├── 上班打卡
│ ├── 下班打卡
│ ├── 考勤记录查询
│ └── 考勤异常申诉
├── 个人信息管理
│ ├── 基本信息维护
│ └── 人脸更新
└── 考勤统计
├── 个人考勤日历
└── 考勤报表导出
3.2 管理员端功能
├── 部门管理
│ ├── 部门增删改查
│ └── 部门人员分配
├── 员工管理
│ ├── 员工信息管理
│ ├── 人脸信息管理
│ └── 账号启停用
├── 考勤规则设置
│ ├── 上班时间设置
│ ├── 下班时间设置
│ ├── 迟到早退阈值
│ └── 节假日设置
├── 考勤审核
│ ├── 异常考勤审核
│ ├── 补卡申请审批
│ └── 批量导入导出
├── 报表统计
│ ├── 部门考勤统计
│ ├── 个人考勤明细
│ └── 图表可视化
└── 系统管理
├── 角色权限管理
├── 操作日志
└── 数据备份
四、数据库设计
4.1 主要数据表结构
-- 部门表
CREATE TABLE department (
id INT PRIMARY KEY AUTO_INCREMENT,
dept_name VARCHAR(50) NOT NULL,
parent_id INT DEFAULT 0,
create_time DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- 员工表
CREATE TABLE employee (
id INT PRIMARY KEY AUTO_INCREMENT,
emp_no VARCHAR(20) UNIQUE NOT NULL,
name VARCHAR(50) NOT NULL,
gender CHAR(1),
phone VARCHAR(20),
email VARCHAR(100),
dept_id INT,
position VARCHAR(50),
face_feature TEXT, -- 人脸特征向量(JSON格式)
face_image VARCHAR(255), -- 人脸图片路径
status TINYINT DEFAULT 1, -- 1:在职 0:离职
create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (dept_id) REFERENCES department(id)
);
-- 考勤记录表
CREATE TABLE attendance (
id INT PRIMARY KEY AUTO_INCREMENT,
emp_id INT,
check_date DATE NOT NULL,
check_in_time DATETIME, -- 上班打卡时间
check_out_time DATETIME, -- 下班打卡时间
in_status VARCHAR(20), -- 正常、迟到、缺卡
out_status VARCHAR(20), -- 正常、早退、缺卡
work_hours DECIMAL(4,2), -- 工作时长
create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (emp_id) REFERENCES employee(id),
UNIQUE KEY uk_emp_date (emp_id, check_date)
);
-- 考勤规则表
CREATE TABLE attendance_rule (
id INT PRIMARY KEY AUTO_INCREMENT,
rule_name VARCHAR(50),
check_in_time TIME NOT NULL, -- 上班时间
check_out_time TIME NOT NULL, -- 下班时间
late_threshold INT DEFAULT 0, -- 迟到阈值(分钟)
early_threshold INT DEFAULT 0, -- 早退阈值(分钟)
work_days VARCHAR(20) DEFAULT '1,2,3,4,5', -- 工作日(周一=1,周日=7)
is_active TINYINT DEFAULT 1
);
-- 请假/补卡申请表
CREATE TABLE leave_apply (
id INT PRIMARY KEY AUTO_INCREMENT,
emp_id INT,
apply_type VARCHAR(20), -- 请假、补卡、外勤
start_time DATETIME,
end_time DATETIME,
reason TEXT,
status VARCHAR(20) DEFAULT '待审批', -- 待审批、通过、驳回
approver_id INT,
approve_time DATETIME,
create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (emp_id) REFERENCES employee(id)
);
五、各语言实现方案
5.1 Java实现方案
核心技术栈:
-
Spring Boot 2.7.x
-
Spring Security + JWT
-
MyBatis Plus
-
OpenCV 4.5
-
MySQL/Redis
-
Vue.js(前端)
人脸识别核心代码示例:
@Service
public class FaceRecognitionService {
@Autowired
private EmployeeMapper employeeMapper;
// 加载OpenCV库
static {
nu.pattern.OpenCV.loadLocally();
}
/**
* 人脸特征提取
*/
public String extractFaceFeature(MultipartFile file) {
Mat image = Imgcodecs.imread(file.getBytes());
// 转换为灰度图
Mat gray = new Mat();
Imgproc.cvtColor(image, gray, Imgproc.COLOR_BGR2GRAY);
// 人脸检测
CascadeClassifier faceDetector = new CascadeClassifier(
"haarcascade_frontalface_alt.xml"
);
MatOfRect faceDetections = new MatOfRect();
faceDetector.detectMultiScale(gray, faceDetections);
Rect[] faces = faceDetections.toArray();
if (faces.length == 0) {
throw new RuntimeException("未检测到人脸");
}
// 提取特征向量(简化版,实际可使用深度学习模型)
Mat face = new Mat(gray, faces[0]);
MatOfFloat featureVector = new MatOfFloat();
// 这里可以使用预训练的深度学习模型提取特征
return convertMatToJson(featureVector);
}
/**
* 人脸比对
*/
public boolean compareFace(String feature1, String feature2, double threshold) {
Mat vec1 = convertJsonToMat(feature1);
Mat vec2 = convertJsonToMat(feature2);
// 计算余弦相似度
double similarity = calculateCosineSimilarity(vec1, vec2);
return similarity > threshold;
}
}
5.2 PHP实现方案(Laravel + OpenCV)
核心技术栈:
-
Laravel 10.x
-
OpenCV for PHP
-
MySQL/Redis
-
JWT认证
-
Bootstrap 5(前端)
人脸识别核心代码:
<?php
namespace App\Services;
use OpenCV\Image as OpenCVImage;
use OpenCV\FaceRecognizer;
class FaceRecognitionService
{
/**
* 人脸检测与特征提取
*/
public function detectFace($imagePath)
{
// 加载图片
$image = OpenCVImage::load($imagePath);
// 转换为灰度图
$gray = $image->cvtColor(OpenCVImage::COLOR_BGR2GRAY);
// 人脸检测
$faceCascade = new OpenCV\CascadeClassifier();
$faceCascade->load('haarcascade_frontalface_alt.xml');
$faces = $faceCascade->detectMultiScale($gray);
if (empty($faces)) {
return null;
}
// 提取人脸区域
$face = $gray->getImageROI($faces[0]);
// 调整大小为统一尺寸
$faceResized = $face->resize(100, 100);
// 提取LBP特征
$lbph = FaceRecognizer::createLBPHFaceRecognizer();
$features = $lbph->compute($faceResized);
return json_encode([
'features' => $features,
'bbox' => $faces[0]
]);
}
/**
* 人脸比对
*/
public function matchFace($features1, $features2)
{
$lbph = FaceRecognizer::createLBPHFaceRecognizer();
$similarity = $lbph->similarity($features1, $features2);
return $similarity;
}
}
5.3 Python实现方案(Flask + face_recognition)
核心技术栈:
-
Flask 2.3.x
-
face_recognition库
-
OpenCV-Python
-
MySQL/Redis
-
JWT认证
-
Vue.js/Element UI(前端)
人脸识别核心代码:
import face_recognition
import cv2
import numpy as np
from flask import Flask, request, jsonify
from flask_sqlalchemy import SQLAlchemy
import base64
import io
from PIL import Image
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:password@localhost/attendance'
db = SQLAlchemy(app)
class Employee(db.Model):
__tablename__ = 'employee'
id = db.Column(db.Integer, primary_key=True)
emp_no = db.Column(db.String(20), unique=True)
name = db.Column(db.String(50))
face_encoding = db.Column(db.Text) # 存储人脸特征编码
class FaceRecognitionService:
@staticmethod
def extract_face_encoding(image_data):
"""
提取人脸特征编码
"""
# 将base64或二进制转换为图像
if isinstance(image_data, str):
# base64格式
image_data = base64.b64decode(image_data.split(',')[1])
image = Image.open(io.BytesIO(image_data))
image = np.array(image)
# 转换为RGB格式
if image.shape[2] == 4:
image = cv2.cvtColor(image, cv2.COLOR_RGBA2RGB)
elif len(image.shape) == 2:
image = cv2.cvtColor(image, cv2.COLOR_GRAY2RGB)
# 检测人脸
face_locations = face_recognition.face_locations(image)
if len(face_locations) == 0:
raise ValueError("未检测到人脸")
# 提取人脸编码
face_encodings = face_recognition.face_encodings(image, face_locations)
if len(face_encodings) == 0:
raise ValueError("无法提取人脸特征")
# 将numpy数组转换为列表存储
encoding_list = face_encodings[0].tolist()
return json.dumps(encoding_list)
@staticmethod
def compare_faces(encoding1, encoding2, threshold=0.6):
"""
比较两个人脸特征
"""
enc1 = np.array(json.loads(encoding1))
enc2 = np.array(json.loads(encoding2))
# 计算欧氏距离
distance = np.linalg.norm(enc1 - enc2)
# 距离越小越相似,通常阈值设为0.6
similarity = 1 - distance
return similarity > threshold, similarity
@app.route('/api/attendance/check', methods=['POST'])
def check_attendance():
"""
考勤打卡接口
"""
try:
data = request.json
emp_no = data.get('emp_no')
image_data = data.get('image') # base64格式
# 查询员工
employee = Employee.query.filter_by(emp_no=emp_no).first()
if not employee:
return jsonify({'code': 404, 'msg': '员工不存在'})
# 提取当前人脸特征
current_encoding = FaceRecognitionService.extract_face_encoding(image_data)
# 比对特征
is_match, similarity = FaceRecognitionService.compare_faces(
employee.face_encoding,
current_encoding
)
if not is_match:
return jsonify({
'code': 401,
'msg': '人脸识别失败,相似度:{:.2f}'.format(similarity)
})
# 记录考勤
now = datetime.now()
today = now.date()
attendance = Attendance.query.filter_by(
emp_id=employee.id,
check_date=today
).first()
if not attendance:
# 上班打卡
attendance = Attendance(
emp_id=employee.id,
check_date=today,
check_in_time=now
)
db.session.add(attendance)
msg = '上班打卡成功'
else:
# 下班打卡
attendance.check_out_time = now
msg = '下班打卡成功'
db.session.commit()
return jsonify({
'code': 200,
'msg': msg,
'data': {
'similarity': float(similarity),
'time': now.strftime('%Y-%m-%d %H:%M:%S')
}
})
except Exception as e:
return jsonify({'code': 500, 'msg': str(e)})
if __name__ == '__main__':
app.run(debug=True)更多推荐



所有评论(0)