500行Python代码实现刷脸考勤系统:从需求分析到核心逻辑
本文详细介绍如何使用500行Python代码构建一个完整的刷脸考勤系统。内容涵盖需求分析、界面设计、数据库建表、人脸特征提取与压缩存储、以及基于欧氏距离的打卡逻辑。系统支持自动/手动录入模式,具备防多脸干扰、工号去重及迟到判定功能,适合Python初学者了解计算机视觉与后端数据交互的实际应用。
系统需求分析与功能目标
需求分析
开发“员工刷脸考勤”系统,采用Python语言实现。系统需通过摄像头采集员工面部信息,核心涉及两个问题:一是确定标识员工面部数据的数据结构,二是将信息持久化存储至数据库,包括合理的表结构设计。基本功能要求是通过摄像头识别面部以完成考勤,主要逻辑为遍历数据库中的员工面部数据并与当前摄像头画面进行比对。此外,需处理摄像头画面中出现多张人脸的情况。扩展功能包括导出每日考勤表,这可拆分为考勤信息的存储与展示两个部分。
系统目标设定
(1) 遵循通用软件界面设计原则,所有操作集成于菜单栏。界面分为两部分:左侧区域展示经程序处理后的摄像头实时视频流,右侧区域作为控制台输出相关信息(如面部信息添加成功/失败及原因、打卡成功/失败及原因)。添加面部信息时需用户交互(如输入信息),此时程序处于阻塞状态;而打卡模式下,程序非阻塞,只要未手动关闭,系统将持续运行并识别前来打卡的员工,这更贴合实际使用场景。
(2) 建立数据库表以存储员工信息和考勤信息。每次录入新员工面部信息时,必须输入工号和姓名,系统会查询数据库以确保无重复后方可录入。录入时仅截取距离屏幕最近的员工面部信息,这是基于实际打卡通常依次进行而非多人并行的考虑。录入提供两种模式:自动模式——识别到人脸后自动连续截图,达到10张后结束录入;手动模式——点击菜单结束录入,截图数量不限。录入结束后,系统从捕获的面部图像中提取人脸特征数据,连同姓名等信息作为一行记录保存至数据库。若未捕获到面部或捕获的面部不属于同一人,则该记录被丢弃。
考勤判定需满足三个条件:面部信息已录入、处于打卡时间段内、且未重复打卡。仅当打卡成功时,打卡人的姓名、工号、日期及时间才会作为一行记录存入数据库,并在控制台输出成功信息;否则输出失败原因。
综上所述,设计目标在于实现系统的规范化与人性化。
如需获取源码,请关注并转发,私信小编“01”领取,同时赠送免费Python学习视频资料。
总体架构与界面设计
总体设计
为实现上述目标一,程序界面初始化分为三部分:第一部分初始化菜单栏,第二部分初始化左侧控制台,第三部分初始化右侧展示面板,确保三者相互独立。数据逻辑部分的初始化也分为两部分:首先是数据库初始化,若数据库或表不存在则新建,存在则加载数据;其次是初始化循环使用的变量(如录入时的员工姓名、工号、截图计数器等),每次录入完成后重置这些变量以准备下一次录入。将这些初始化语句封装为函数可提高代码复用率。
目标二主要涉及限制性条件,可通过添加判断语句实现,例如对输入工号ID的合法性检验:
while self.id == ID_WORKER_UNAVIABLE:
self.id = wx.GetNumberFromUser(message="请输入您的工号(-1不可用)",prompt="工号", caption="温馨提示", value=ID_WORKER_UNAVIABLE, parent=self.bmp,max=100000000,min=ID_WORKER_UNAVIABLE)
for knew_id in self.knew_id:
if knew_id == self.id:
self.id = ID_WORKER_UNAVIABLE
wx.MessageBox(message="工号已存在,请重新输入", caption="警告")
其中ID_WORKER_UNAVIABLE为ID的初始值-1,表示不可用。self.knew.id是从数据库加载的ID列表。若ID非法(已存在或不在0~100000000范围内),系统将不断弹出提示框要求重新输入ID。
再例如,针对拒绝处理多张人脸的情况,系统仅处理距离屏幕最近的员工面部信息:
if len(dets) != 0:
biggest_face = dets[0]
#取占比最大的脸
maxArea = 0
for det in dets:
w = det.right() - det.left()
h = det.top()-det.bottom()
if w*h > maxArea:
biggest_face = det
maxArea = w*h
dets为侦测到的所有面部数组,biggest_face为距离屏幕最近的面部对象。
程序流程图如下:
注:图片如看不清可在线预览
https://www.processon.com/view/link/5bbcc953e4b08faf8c7324a1
核心设计原则与函数实现
本程序的设计思想主要包含以下几个方面:
面向对象原则:整个程序主体为一个WAS(WorkAttendanceSystem类,所有实现均围绕该类展开。界面与数据逻辑分离原则:WAS类的初始化过程包括界面初始化和数据初始化,两者相互独立。代码封装原则:将多次调用的语句集封装为接口供调用,消除冗余代码。接口隔离原则:使用多个专门接口而非单一总接口。以下是函数清单。
注:所有类内函数的第一个参数为self,表明该函数属于该类,后文不再赘述。
def __init__(self)
WAS类的构造函数,主要完成初始化操作,包括初始化菜单、信息打印面板、主展示面板,以及初始化数据库加载和循环使用的变量。
def initMenu(self):
完成菜单的初始化显示,并绑定点击事件。
def initInfoText(self):
完成左侧信息提示面板的初始化显示。
def initGallery(self):
完成右侧主展示面板的初始化显示。
def initDatabase(self):
数据库初始化,建立数据库连接(若数据库inspurer.db不存在则新建)。若数据库中不存在员工信息表worker_info和考勤日志表logcat,则依次创建。
def loadDataBase(self,type):
该模块函数用于从数据库读取数据,包括员工信息和考勤信息。第二个参数type用于标识加载的是员工信息还是考勤信息。这样做一方面可以统一接口,打开数据库、获取游标和关闭连接的操作相同,合二为一可提高代码复用率;另一方面可减少加载工作量,减少IO操作,提高程序运行速度。最后,由于读取信息前会清空上一次读取的列表,使用type标识可避免读取一个表时对另一个表造成误操作。
def insertARow(self,Row,type):
该模块函数用于向数据库写入数据,第二个参数为准备写入的一条记录,第三个参数type表示目标表。
def adapt_array(self,arr):
将提取的人脸特征信息(列表)进行压缩,入口参数为待压缩数据,出口参数为压缩后的数据,用于写入数据库。
def convert_array(self,text):
将读取出的数据解压缩为人脸特征信息,入口参数为待解压数据,出口参数为解压后的数据。
def return_euclidean_distance(feature_1, feature_2):
计算两个人脸的欧氏距离,入口参数为两个人脸的特征数据,出口参数为判定结果。欧氏距离大于0.4判定为不同人脸,不大于0.4判定为相同人脸。
def OnNewRegisterClicked(self,event):
见名知义,这是菜单中新建录入的监听事件,参数event为事件信息。其他菜单(OnFinishRegisterClicked, OnStartPunchCardClicked, OnEndPunchCardClicked, OnOpenLogcatClicked, OnCloseLogcatClicked)的监听事件类似,在此不再赘述。
def getDateAndTime(self):
获取当前日期和时间,并组装成特定格式作为出口参数返回。函数调用关系如图箭头所示,箭头指向被调用者。
在线预览地址:
https://www.processon.com/view/link/5bbe0b0de4b0534c9bfbecb4
运行结果与日志展示
程序运行结果:程序主界面
新建录入界面
我们可以看到,信息栏显示人脸数据重复警告,本次录入被取消。
因此,我们将数据库数据删除后重新操作。
以下是打印的日志信息(为保证格式,复制到记事本后截图)。
可以看到录入已成功。
开始打卡
提示信息打印如下。
迟到与不迟到的临界时间为9:00。
展示日志
只有已录入且首次成功签到的记录才会写入数据库,无论是否迟到。
总结
以上所述是小编给大家介绍的500行Python代码打造刷脸考勤系统,希望对大家有所帮助。如果大家有任何疑问请留言,小编会及时回复。在此非常感谢大家对本站的支持! 如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









