Python OpenCV开发MR智能人脸识别打卡系统(四服务模块设计)

Posted showswoller

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python OpenCV开发MR智能人脸识别打卡系统(四服务模块设计)相关的知识,希望对你有一定的参考价值。

需要源码请点赞关注收藏后评论区留言私信~~~

整体系统讲解如下

Python OpenCV开发MR智能人脸识别打卡系统(一、需求分析与系统设计)

Python OpenCV开发MR智能人脸识别打卡系统(二、文件系统、数据实体模块设计)

Python OpenCV开发MR智能人脸识别打卡系统(三、工具模块设计)

Python OpenCV开发MR智能人脸识别打卡系统(五、程序入口设计与测试)

本系统的服务模块包含两个文件:hr_service.py和rocognize_service.py,前者提供所有人事管理的相关功能,例如增减员工,查询员工数据,后者提供人脸识别服务

一、人事服务模块

该模块包含以下功能:

添加新员工

删除某员工

为指定员工添加打卡记录

多种获取员工新的方法

生成考勤日报

生成考勤月报

1:导入模块

人事服务需要管理员工类列表,记录打卡时间,还要计算,对比负责的日期和时间数值,所以要导入数据实体模块,公共工具模块,时间模块和日历模块


from entity import organizations as o
from util import public_tools as tool
from util import io_tools as io
import datetime
import calendar

2:加载所有数据

程序启动时运行此方法就可以一次性载入所有保存在文件中的数据,该方法依次进行文件自检,载入管理员账号密码,打卡记录,员工信息和员工照片

def load_emp_data():
    io.checking_data_files()  # 文件自检
    io.load_users()  # 载入管理员账号
    io.load_lock_record()  # 载入打卡记录
    io.load_employee_info()  # 载入员工信息
    io.load_employee_pic()  # 载入员工照片

3:添加新员工

def add_new_employee(name):
    code = tool.randomCode()  # 生成随机特征码
    newEmp = o.Employee(o.get_new_id(), name, code)  # 创建员工对象
    o.add(newEmp)  # 组织结构中添加新员工
    io.save_employee_all()  # 保存最新的员工信息
    return code  # 新员工的特征码

4:删除员工

# 删除某个员工
def remove_employee(id):
    io.remove_pics(id)  # 删除该员工所有图片
    o.remove(id)  # 从组织结构中删除
    io.save_employee_all()  # 保存最新的员工信息
    io.save_lock_record()  # 保存最新的打卡记录

5:添加打卡记录

def add_lock_record(name):
    record = o.LOCK_RECORD  # 所有打卡记录
    now_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")  # 当前时间
    if name in record.keys():  # 如果这个人有打卡记录
        r_list = record[name]  # 去除他的记录
        if len(r_list) == 0:  # 如果记录为空
            r_list = list()  # 创建新列表
        r_list.append(now_time)  # 记录当前时间
    else:  # 如果这个人从未打过卡
        r_list = list()  # 创建新列表
        r_list.append(now_time)  # 记录当前时间
        record[name] = r_list  # 将记录保存在字典中
    io.save_lock_record()  # 保存所有打卡记录

打卡时间规则如下

 6:获取员工数据

人事服务提供了多种获取员工数据的方法,可以满足多种业务场景

def get_employee_report():
    # report = list()   # 员工信息列表
    report = "###########################################\\n"
    report += "员工名单如下:\\n"
    i = 0  # 换行计数器
    for emp in o.EMPLOYEES:  # 遍历所有员工
        report += "(" + str(emp.id) + ")" + emp.name + "\\t"
        i += 1  # 计数器自增
        if i == 4:  # 每四个员工换一行
            report += "\\n"
            i = 0  # 计数器归零
    report = report.strip()  # 清除报表结尾可能出现的换行符
    report += "\\n###########################################"
    return report

7:验证管理员账号和密码

只有管理员账号密码都正确的情况下,才可以正确登录

def valid_user(username, password):
    if username in o.USERS.keys():  # 如果有这个账号
        if o.USERS.get(username) == password:  # 如果账号和密码匹配
            return True  # 验证成功
    return False  # 验证失败

8:保存上下班时间

第一个参数为上班时间,第二个参数为下班时间

def save_work_time(work_time, close_time):
    o.WORK_TIME = work_time
    o.CLOSING_TIME = close_time
    io.save_work_time_config()  # 上下班时间保存到文件中

9:打印考勤日报

方法中分别创建了迟到 早退和缺席名单三个列表,只要某员工出现不正常打卡记录,就会将该员工姓名放到对应不正常打卡状态的名单里,最后打印报表,给出各名单人数和明细

# 打印指定日期的打卡日报
def get_day_report(date):
    io.load_work_time_config()  # 读取上下班时间

    earliest_time = datetime.datetime.strptime(date + " 00:00:00", "%Y-%m-%d %H:%M:%S")  # 今天0点
    noon_time = datetime.datetime.strptime(date + " 12:00:00", "%Y-%m-%d %H:%M:%S")  # 今天中午12点
    latest_time = datetime.datetime.strptime(date + " 23:59:59", "%Y-%m-%d %H:%M:%S")  # 今晚0点之前
    work_time = datetime.datetime.strptime(date + " " + o.WORK_TIME, "%Y-%m-%d %H:%M:%S")  # 上班时间
    closing_time = datetime.datetime.strptime(date + " " + o.CLOSING_TIME, "%Y-%m-%d %H:%M:%S")  # 下班时间

    late_list = []  # 迟到名单
    left_early = []  # 早退名单
    absent_list = []  # 缺席名单

    for emp in o.EMPLOYEES:  # 遍历所有员工
        if emp.name in o.LOCK_RECORD.keys():  # 如果该员工有打卡记录
            emp_lock_list = o.LOCK_RECORD.get(emp.name)  # 获取该员工所有的打卡记录
            is_absent = True  # 缺席状态
            for lock_time_str in emp_lock_list:  # 遍历所有打卡记录
                lock_time = datetime.datetime.strptime(lock_time_str, "%Y-%m-%d %H:%M:%S")  # 打卡记录转为日期格式
                if earliest_time < lock_time < latest_time:  # 如果当天有打卡记录
                    is_absent = False  # 不缺席
                    if work_time < lock_time <= noon_time:  # 上班时间后、中午之前打卡
                        late_list.append(emp.name)  # 加入迟到名单
                    if noon_time < lock_time < closing_time:  # 中午之后、下班之前打卡
                        left_early.append(emp.name)  # 加入早退名单
            if is_absent:  # 如果仍然是缺席状态
                absent_list.append(emp.name)  # 加入缺席名单
        else:  # 该员工没有打卡记录
            absent_list.append(emp.name)  # 加入缺席名单

    emp_count = len(o.EMPLOYEES)  # 员工总人数
    print("--------" + date + "--------")
    print("应到人数:" + str(emp_count))
    print("缺席人数:" + str(len(absent_list)))
    absent_name = ""  # 缺席名单
    if len(absent_list) == 0:  # 如果没有缺席的
        absent_name = "(空)"
    else:  # 有缺席的
        for name in absent_list:  # 遍历缺席列表
            absent_name += name + " "  # 拼接名字
    print("缺席名单:" + absent_name)
    print("迟到人数:" + str(len(late_list)))
    late_name = ""  # 迟到名单
    if len(late_list) == 0:  # 如果没有迟到的
        late_name = "(空)"
    else:  # 有迟到的
        for name in late_list:  # 遍历迟到列表
            late_name += name + " "  # 拼接名字
    print("迟到名单:" + str(late_name))
    print("早退人数:" + str(len(left_early)))
    early_name = ""  # 早退名单
    if len(left_early) == 0:  # 如果没有早退的
        early_name = "(空)"
    else:  # 有早退的
        for name in left_early:  # 遍历早退列表
            early_name += name + " "  # 拼接名字
    print("早退名单:" + early_name)

10:生成考勤月报

与考勤日报不同,考勤月报是一种汇总形式的报表,可以展示员工整个月的考勤状态,因为月报表内容较多,所以不会在控制台中展示,而是生成独立的报表文件 

用记事本打开CSV格式的月报

用Office Excel打开CSV格式的月报

# 创建指定月份的打卡记录月报
def get_month_report(month):
    io.load_work_time_config()  # 读取上下班时间
    date = datetime.datetime.strptime(month, "%Y-%m")  # 月份转为时间对象
    monthRange = calendar.monthrange(date.year, date.month)[1]  # 该月最后一天的天数
    month_first_day = datetime.date(date.year, date.month, 1)  # 该月的第一天
    month_last_day = datetime.date(date.year, date.month, monthRange)  # 该月的最后一天

    clock_in = "I"  # 正常上班打卡标志
    clock_out = "O"  # 正常下班打卡标志
    late = "L"  # 迟到标志
    left_early = "E"  # 早退标志
    absent = "A"  # 缺席标志

    lock_report = dict()  # 键为员工名,值为员工打卡情况列表

    for emp in o.EMPLOYEES:
        emp_lock_data = []  # 员工打卡情况列表
        if emp.name in o.LOCK_RECORD.keys():  # 如果员工有打卡记录
            emp_lock_list = o.LOCK_RECORD.get(emp.name)  # 从打卡记录中获取该员工的记录
            index_day = month_first_day  # 遍历日期,从该月第一天开始
            while index_day <= month_last_day:
                is_absent = True  # 缺席状态
                earliest_time = datetime.datetime.strptime(str(index_day) + " 00:00:00", "%Y-%m-%d %H:%M:%S")  # 当天0点
                noon_time = datetime.datetime.strptime(str(index_day) + " 12:00:00", "%Y-%m-%d %H:%M:%S")  # 当天中午12点
                latest_time = datetime.datetime.strptime(str(index_day) + " 23:59:59", "%Y-%m-%d %H:%M:%S")  # 当天0点之前
                work_time = datetime.datetime.strptime(str(index_day) + " " + o.WORK_TIME,
                                                       "%Y-%m-%d %H:%M:%S")  # 当天上班时间
                closing_time = datetime.datetime.strptime(str(index_day) + " "
                                                          + o.CLOSING_TIME, "%Y-%m-%d %H:%M:%S")  # 当天下班时间
                emp_today_data = ""  # 员工打卡标记汇总

                for lock_time_str in emp_lock_list:  # 遍历所有打卡记录
                    lock_time = datetime.datetime.strptime(lock_time_str, "%Y-%m-%d %H:%M:%S")  # 打卡记录转为日期格式
                    if earliest_time < lock_time < latest_time:  # 如果当前日期有打卡记录
                        is_absent = False  # 不缺席
                        if lock_time <= work_time:  # 上班时间前打卡
                            emp_today_data += clock_in  # 追加正常上班打卡标志
                        elif lock_time >= closing_time:  # 下班时间后打卡
                            emp_today_data += clock_out  # 追加正常下班打卡标志
                        elif work_time < lock_time <= noon_time:  # 上班时间后、中午之前打卡
                            emp_today_data += late  # 追加迟到标志
                        elif noon_time < lock_time < closing_time:  # 中午之后、下班之前打卡
                            emp_today_data += left_early  # 追加早退标志
                if is_absent:  # 如果缺席
                    emp_today_data = absent  # 直接赋予缺席标志
                emp_lock_data.append(emp_today_data)  # 员工打卡标记添加到打卡情况列表中
                index_day = index_day + datetime.timedelta(days=1)  # 遍历天数递增
        else:  # 没有打卡记录的员工
            index_day = month_first_day  # 从该月第一天开始
            while index_day <= month_last_day:  # 遍历整月
                emp_lock_data.append(absent)  # 每天都缺席
                index_day = index_day + datetime.timedelta(days=1)  # 日期递增
        lock_report[emp.name] = emp_lock_data  # 将打卡情况列表保存到该员工之下

    report = "\\"姓名/日期\\""  # cvs文件的文本内容,第一行第一列
    index_day = month_first_day  # 从该月第一天开始
    while index_day <= month_last_day:  # 遍历整月
        report += ",\\"" + str(index_day) + "\\""  # 添加每一天的日期
        index_day = index_day + datetime.timedelta(days=1)  # 日期递增
    report += "\\n"

    for emp in lock_report.keys():  # 遍历报表中的所有员工
        report += "\\"" + emp + "\\""  # 第一列为员工名
        data_list = lock_report.get(emp)  # 取出员工的打卡情况列表
        for data in data_list:  # 取出每一天的打卡情况
            text = ""  # CSV中显示的内容
            if absent == data:  # 如果是缺席
                text = "【缺席】"
            elif clock_in in data and clock_out in data:  # 如果是全勤,不考虑迟到和早退
                text = ""  # 显示空白
            else:  # 如果不是全勤
                if late in data and clock_in not in data:  # 有迟到记录且无上班打卡
                    text += "【迟到】"
                if left_early in data and clock_out not in data:  # 有早退记录且无下班打卡
                    text += "【早退】"
                if clock_out not in data and left_early not in data:  # 无下班打卡和早退记录
                    text += "【下班未打卡】"
                if clock_in not in data and late not in data:  # 有无上班打卡和迟到记录
                    text += "【上班未打卡】"
            report += ",\\"" + text + "\\""
        report += "\\n"

    title_date = month_first_day.strftime("%Yy%mm").format(y="年", m="月")  # csv文件标题日期
    file_name = title_date + "考勤月报"  # CSV的文件名
    io.create_CSV(file_name, report)  # 生成csv文件

二、人脸识别服务模块

该模块提供以下功能

检测图像中是否有正面人脸

判断图像中的人脸属于哪个人

1:导入模块


import cv2
import numpy as np
import os

2:全局变量

RECOGNIZER = cv2.face.LBPHFaceRecognizer_create()  # LBPH识别器
# RECOGNIZER = cv2.face.EigenFaceRecognizer_create()#特征脸识别器
# RECOGNIZER = cv2.face.FisherFaceRecognizer_create()  # LBPH识别器
PASS_CONF = 45  # 最高评分,LBPH最高建议用45,特征脸最高建议用22000

3:训练识别器

# 训练识别器
def train(photos, lables):
    RECOGNIZER.train(photos, np.array(lables))  # 识别器开始训练

4:发现人脸

用来判断图像中是否有正面人脸,参数为灰度图像,通过正面人脸获取级联分类器对检测图像中出现的人脸数量


# 识别器识别图像中的人脸
def recognise_face(photo):
    label, confidence = RECOGNIZER.predict(photo)  # 识别器开始分析人脸图像
    if confidence > PASS_CONF:  # 忽略评分大于最高评分的结果
        return -1
    return label

5:识别人脸

该方法用来识别图像中的人脸属于哪位员工,方法参数为被识别的图像,该方法必须在识别器接收完训练之后被调用,识别器给出分析得出的评分,如果评分大于可信范围,则认为图像中不存在任何已有员工,返回-1,否则返回已有员工的特征码

# 判断图像中是否有正面人脸
def found_face(gary_img):
    faces = FACE_CASCADE.detectMultiScale(gary_img, 1.15, 4)  # 找出图像中所有的人脸
    return len(faces) > 0  # 返回人脸数量大于0的结果

创作不易 觉得有帮助请点赞关注收藏~~~

以上是关于Python OpenCV开发MR智能人脸识别打卡系统(四服务模块设计)的主要内容,如果未能解决你的问题,请参考以下文章

Python OpenCV开发MR智能人脸识别打卡系统(五程序入口设计与测试)

Python人脸识别智能考勤系统 (供源码,附报告)(可答疑,可调试)

qt+opencv实现人脸识别打卡系统2.0

OpenCV-Python实战(17)——人脸识别详解

2020版最新|千锋人工智能OpenCV人脸识别开发教程 手把手教你掌握前沿技术

AI人工智能之基于OpenCV+face_recognition实现人脸识别