当前位置: 首页 > 科技观察

500行Python代码打造刷脸考勤系统,其实也就那么简单

时间:2023-03-17 21:34:52 科技观察

500行Python代码打造一个人脸识别考勤系统,其实就是这么简单问题在于,一个是应该用什么样的数据来识别每个员工的面部信息,另一个是将这些信息持久化到数据库中。更详细一点,还涉及到表的设计;另一个基本需求是通过摄像头识别员工面部信息完成考勤。这个问题基本上可以通过遍历数据库中的员工人脸数据,比对当前摄像头中的员工人脸数据来解决,但是有个问题就是如果摄像头里面有多个人脸,怎么处理。扩展需求是导出每日考勤表,可以拆分为两部分,一是存储考勤信息,二是展示考勤信息。我们希望达到的目标是:(1)遵循通用软件界面设计原则,所有操作都在菜单栏中实现,部分区域用于实时显示摄像头读取的视频流信息程序处理时间和处理,另一部分区域做控制台输出,打印相关信息,如提示员工添加人脸信息成功,添加失败及原因,提示员工签到成功,签到失败及原因原因;添加人脸信息时,人必须和程序进行交互,比如输入一些相关信息,此时程序被屏蔽;但是签到的时候,程序没有被屏蔽,如果不点击关闭签到,它会一直处于签到模式,等待和识别每一个前来签到的员工,这个比较符合现实的使用场景。(2)创建一张表,存放员工信息和考勤信息。每次新建员工人脸信息录入时,都需要填写工号和姓名,检查无重复后方可录入。进入时,只采集离屏幕最近的员工的面部信息。这是因为实际签到是按顺序完成的,而不是由一群人完成的。进入时有两种模式可供选择,自动模式:一旦识别到人脸,将自动截图,连续截图达到10张时结束进入;手动模式:点击菜单结束进入,它没有必要得到10张。录入完成后,会从刚刚抓拍到的员工人脸中提取人脸特征数据,与之前录入的员工姓名等数据一起存入数据库,作为一行记录。如果没有抓到员工人脸或者刚刚抓到的人脸信息不是同一个人,则丢弃该Row记录。考勤时必须满足三个条件:已录入人脸信息、在签到时间段内、未重复签到。只有签到成功后,签到人的姓名、工号、签到日期和时间才会作为一条记录保存到数据库中,存入数据库。控制台输出登录成功信息,否则控制台输出登录失败及其原因信息。总而言之:我们的设计目标是标准化和人性化。需要源码的可以关注,转发,私信小编“01”领取,还有免费Python学习视频资料赠送。总体设计为了完成上述目标1,程序的界面初始化分为三部分,第一部分初始化菜单栏,第二部分初始化左侧控制台,第三部分初始化右侧显示面板,使得这三个部分相互独立;数据逻辑部分的初始化分为两部分。第一部分是数据库部分的初始化。如果数据库/表不存在,则创建,如果存在,则加载相关数据。第二部分是初始化一些需要回收的变量,比如创建新条目的时候。员工姓名、工号、截图数计数器等,每次录入完成后,这些数据都要重新初始化,以便下次录入。将这些初始化语句写成一个函数可以提高代码重用。上面的目标2主要是一些限制条件,可以通过加入判断语句来实现,比如检查输入id的合法性:工号(-1不可用)",prompt="工号",caption="温馨提示",value=ID_WORKER_UNAVIABLE,parent=self.bmp,max=100000000,min=ID_WORKER_UNAVIABLE)forknew_idinself.knew_id:ifknew_id==自己。id:self.id=ID_WORKER_UNAVIABLEwx.MessageBox(message="工号已存在,请重新输入",caption="Warning")其中ID_WORKER_UNAVIABLE为id-1的初始化值,不可用,self.knew.id为从数据库中加载的id列表,如果id不合法(在0~100000000内重复或不重复),总会有新的弹窗提示输入id。再比如,在拒绝多张人脸时,只处理距离屏幕最近的员工的人脸信息:iflen(dets)!=0:biggest_face=dets[0]#获取比例最大的人脸maxArea=0fordetindets:w=det.right()-det.left()h=det.top()-det.bottom()ifw*h>maxArea:biggest_face=detmaxArea=w*hdets是检测到的所有人脸的数组,biggest_face是距离从屏幕上看最近的面部表情。程序框图:注:图片看不清楚也可以在线预览https://www.processon.com/view/link/5bbcc953e4b08faf8c7324a1本程序的设计思路大致可以分为以下几个方面:面向对象原则,整个程序主体是一个WAS(WorkAttendanceSystem)类,所有的实现都围绕着这个类。基于接口和数据逻辑分离的原则,WAS类的初始化过程包括接口初始化和数据初始化,两者相互独立。代码封装原则,将多次调用的语句集写成调用接口,不存在冗余代码。接口隔离原则:使用多个专用接口而不是单个通用接口。函数列表注意:类中所有函数的第一个参数都是self,表示该函数属于本类,def__init__(self)WAS类的构造函数后面不再赘述,主要是完成一些初始化操作,如初始化菜单、信息打印面板、主显示面板、初始化加载数据库、初始化循环中使用的变量等。definitMenu(self):完成菜单的初始化显示,点击事件绑定。definitInfoText(self):完成左侧信息提示面板的初始化显示。definitGallery(self):完成右侧主显示面板的初始化显示。definitDatabase(self):初始化数据库,建立数据库连接(如果数据库inspurer.db不存在,先新建一个),如果数据库中不存在员工信息worker_info和考勤logcat这两个表,依次创建它们。defloadDataBase(self,type):该模块函数完成从数据库中读取数据的操作,包括读取员工信息和考勤信息。第二个参数类型用于标识是加载员工信息还是考勤信息。一方面可以统一接口,打开数据库等同于获取游标和关闭连接,将两个读取接口合二为一,提高代码复用;另一方面可以减少加载的工作量,减少IO,提高程序的运行速度;***,因为上次读取的信息列表在读取信息前会被清空,所以使用类型标记可以避免从一张表读取到另一张表造成的误操作。definsertARow(self,Row,type):该模块函数完成对数据库的写操作,第二个参数是要写入的记录,第三个参数type表示写入到哪个表。defadapt_array(self,arr):对提取的人脸特征信息(list)进行压缩,入口参数为要压缩的数据,出口参数为写入数据库的压缩数据。defconvert_array(self,text):将读取到的数据解压成面部特征信息,入口参数为要解压的数据,出口参数为解压后的数据。defreturn_euclidean_distance(feature_1,feature_2):计算两个面之间的欧式距离。入口参数是两个人脸的特征数据,出口参数是判断的结果。如果欧氏距离大于0.4,则判断为不同,如果不大于,则判断为相同。defOnNewRegisterClicked(self,event):顾名思义就是菜单中新进入的监听事件,参数event为事件信息,其他菜单(OnFinishRegisterClicked、OnStartPunchCardClicked、OnEndPunchCardClicked、OnOpenLogcatClicked、OnCloseLogcatClicked)类似,不会在这里描述。defgetDateAndTime(self):获取当前日期和时间,将其组装成特定格式并作为导出参数返回。函数调用关系:箭头指向被调用者在线预览地址:https://www.processon.com/view/link/5bbe0b0de4b0534c9bfbecb4程序运行结果程序主界面新建入口我们看到信息栏有重复警告对于人脸数据,这次Entry取消了。于是我们删除了数据库数据,重新开始。下面是打印出来的日志信息(保证格式,复制到记事本截图中),看到已经输入成功了。启动签到提示信息打印如下。迟到与否的关键时间是9:00。显示日志只会在已经输入并且第一次成功签到时写入数据库,不管你有没有迟到。

猜你喜欢