基于人脸识别的课堂考勤系统 tkinter+openpyxl+face_recognition

本项目结合了上一篇文章基于face_recognition库实现人脸识别,通过利用Python的tkinter模块来设计考勤系统的图形化界面,此外结合openpyxl模块,实现将学生的信息和考勤打卡数据保存到表格中,方便查看和调用。该系统具备“刷脸打卡”、“新学生注册”等功能。

一、界面效果

主界面
在主界面分别按下“新学生注册”按钮和“刷脸打卡”按钮的过程效果如图:
实现过程

二、开发环境

Windows10+python3.5.5+Vs Code(开发工具)

三、开发准备

在桌面新建一个工作薄,命名为Data.xlsx(见文章最后,附完整程序和表格链接)其中有两个小表格,分别是“学生信息表”和“学生考勤表”,在第一列和第二列填写如下信息。见文末链接。
Data工作薄

四、实现过程

1. 导入相关库函数
注意face_recognition库没有的话需要pip install face_recognition进行安装。

import cv2  #OpenCV库
import openpyxl  #openpyxl库
import os  #操作系统相关库,标准库
import time  #time库
import tkinter.messagebox  #messagebox消息框模块
from tkinter import *  #tkinter库
import face_recognition

2. 主界面程序设计
*(主界面程序放在最后,这里提前解释)*主界面放置了一个“刷脸打卡”、“新学生注册”、“退出系统”按钮。

#主界面程序
top = Tk()
top.title("考勤系统")  #窗口标题
top.geometry("500x300")  #窗口尺寸大小
#主界面的框架组件main_frame
main_frame = Frame(top) #第一层框架组件
main_frame.place(relwidth=1,relheight= 1)  #参数设置为1表示框架铺满整个窗口
Label(main_frame,text = "智能课堂考勤系统",bg = "white",font = ("黑体",20),
width = 35,height = 2).place(x = 0,y = 0)  #放置“智能课堂考勤系统”标签
Button(main_frame,text = "刷脸打卡",bg = "green",font = ("黑体",12),width = 12,height = 2,
command = take_photo).place(x = 30,y = 150)  #放置“刷脸打卡”按钮
Button(main_frame,text = "新学生注册",bg = "green",font = ("黑体",12),width = 12,height = 2,
command = register).place(x = 200,y = 150)  #放置“新学生注册”按钮
Button(main_frame,text = "退出系统",bg = "green",font = ("黑体",12),width = 12,height = 2,
command = top.destroy).place(x =360,y = 150)  #放置“退出系统”按钮,destroy()直接销毁窗口
#定义文件路径
path = "C:/Users/Administrator/Desktop/face/"  #face文件夹
path0 = "C:/Users/Administrator/Desktop/"  #桌面
top.mainloop()  #进入进入等待与处理窗口事件

3. 拍照函数get_photo()
该函数用于调用笔记本摄像头或者其他外接摄像头。打开摄像头,然后通过capture.read()获取其中某一帧图像,通过cv2.imwrite()将图像保存到指定的路径,参数img是拍摄的图片名称,也包含指定的路经。

#拍摄照片函数
def get_photo(img):  #i参数mg,是拍摄的图片名称,也包含指定的路经
    capture = cv2.VideoCapture(0, cv2.CAP_DSHOW)  #打开摄像头,参数0是摄像头端口,可以更换
    ref,frame=capture.read()  #将摄像头中的一帧数据保存下来
    cv2.imwrite(img,frame)  #将图片保存下来
    cv2.imshow(img,frame)  #窗口显示
    cv2.waitKey(1000) #延时1000ms,即1s
    cv2.destroyAllWindows()  #关闭窗口
    return img  #返回图片数据

4. 刷脸打卡函数take_photo()
在主界面按下“刷脸打卡”按钮后,跳转到该函数。通过调用get_photo()函数来拍摄一张学生刷脸的临时图片,将该图片进行图像处理编码后,通过os.listdir()方法遍历face文件夹里面的图片(这些图片同样需要进行图像处理编码),然后通过face_recognition.compare_faces进行人脸对比,人脸对比成功,获取图片的编号,通过编号num定位验证者在表格中的位置,然后将打卡时间和打卡日期填写在表格中。如果验证失败人脸标志位flag为0

#刷脸打卡函数
def take_photo():
    print("刷脸打卡")
    student = face_recognition.load_image_file(get_photo(path0 + "img.jpg" )) #加载人脸图像,参数调用拍照函数,获取一张验证者的图像
    student_rgb =cv2.cvtColor(student,cv2.COLOR_BGR2RGB)  #图像类型转换函数   
    student_encode = face_recognition.face_encodings(student_rgb)[0]  #给定一个图像,返回图像中每个面的128维人脸编码
    #返回face文件夹里面的内容,要从人脸库face文件夹中,获取验证者的身份
    pathDir = os.listdir(path)  #返回的是文件夹里的每一张图片
    flag = 0  #人脸标志位
    #测试另外一张图像
    for i in pathDir: #遍历6张图片
        face = face_recognition.load_image_file(path + i) #将文件夹里的每一张图片打开
        face_rgb = cv2.cvtColor(face,cv2.COLOR_BGR2RGB)  #将文件夹里的每一张图片进行转换
        face_encode = face_recognition.face_encodings(face_rgb)[0]  #将图像编码
        #compare_faces比较脸部编码列表和face文件夹内的候选编码,看看它们是否匹配,匹配成功返回[True]
        s = face_recognition.compare_faces([student_encode],face_encode,tolerance=0.49)  #参数tolerance是两张脸之间有多少距离才算匹配。该值越小对比越严格,0.49是我测出来最佳的
        if s == [True] :  #如果匹配成功则返回的是布尔型列表里的True
            flag = 1  #成功的话将标志位赋值为1
            num = i[:len(i)-4]  #获取图片的编号,去掉“.jpg”。例如是照片“7.jpg”,这里num就是7,就是注册者的编号
            break  #直接跳出循环
        else:
            flag = 0  #没有匹配成功则标志位为0
    if flag ==1:  #通过编号num在表格中找到验证者的位置
        #表格操作
        sheets = openpyxl.load_workbook(path0 + "Data.xlsx")  #打开“学生信息表”工作薄
        sheet1 = sheets[sheets.sheetnames[0]]  #获取Data工作薄里面的第一个表“学生信息表”
        max_row1 = sheet1.max_row  #获取第一个表格有数据最后一行的行数
        print("验证者的编号是:" , num)  #输出对比结果
        #print(type(num),type(sheet1.cell(max_row1,1).value))
        for j in range(2,max_row1+1):  #遍历‘学生信息表’
            if sheet1.cell(j,1).value == str(num):  #根据编号定位到对应学生在表格中的位置,例如杰克的编号是1,num=1,从“学生信息表”中第一列找到编号是1的那一行j,也就是第二行
                name = sheet1.cell(j,2).value    #获取学生姓名
                #获取当前打卡日期、时间,统计到学生考勤表
                date = time.strftime("%Y-%m-%d",time.localtime()) #当天日期
                Time = time.strftime("%H:%M",time.localtime()) #签到的时间
                #打开学生考勤表,将学生的打卡日期添加到工作薄中
                sheet2 = sheets[sheets.sheetnames[1]]  #获取Data工作薄里面的第二个表“学生考勤表”
                max_row2 = sheet2.max_row  #获取表格有数据最后一行的行数
                sheet2.cell(row = max_row2+1,column=1,value = date)  #写入签到日期
                sheet2.cell(row = max_row2+1,column=2,value = name)  #写入签到学生
                sheet2.cell(row = max_row2+1,column=3,value = Time)  #写入签到打卡时间
                sheets.save(path0 + "Data.xlsx")  #保存到Data工作薄
                print(str(sheet1.cell(j,2).value) +"签到成功," + "打卡时间是" + Time)  #播报签到情况
                tkinter.messagebox.showinfo(title="提示",message=name + "打卡成功,"+ "打卡时间是" + Time)  #消息方框
                break  #跳出当前遍历循环

5. 注册函数register()
在主界面按下“新学生注册”按钮后,跳转到该函数。实现覆盖原来的框架组件main_frame,布局新的框架组件second_frame,用来放置新界面需要的按钮、标签组件。“确认”按钮关联Message函数,用来确认、保存新学生的注册信息的

#注册函数
def register():
    print("注册")
    main_frame.place_forget()  #隐藏main_frame框架
    second_frame = Frame(top)  #定义第二个框架second_frame,用于注册界面
    second_frame.place(relwidth=1,relheight= 1)  
    #布置新界面的组件:标签,输入文本框,按钮
    Label(second_frame,text = "欢迎使用人脸识别系统",font = ("黑体",18),
    width = 40,height = 2).place(x = 20,y = 0)
    Label(second_frame,text = "姓名",font = ("黑体",12),
    width = 20,height = 1).place(x = 50,y = 100)  #提示文字“姓名”
    name_entry = Entry(second_frame, font=("黑体", 12), width=20)
    name_entry.place(x = 240,y = 100)  #文本框组件,用于填写“姓名”
    Button(second_frame,text = "确认",font = ("黑体",12), width=10,
    command=lambda:Message(name_entry)).place(x = 100,y = 150)  #确认按钮
    Button(second_frame,text = "返回",font = ("黑体",12), width=10,
    command=lambda:back_main(second_frame)).place(x = 300,y = 150)  #返回按钮

6. 学生信息存储Message()
点击“确认”按钮后,该函数操作表格获取表格中有数据最后一行的行数max_row,作为新注册学生的序号,如下图所示。以该编号为新生图片命名“max_row.jpg”,然后调用摄像头给新学生拍照保存到face文件夹内。将学生的姓名、序号填写到“学生信息”表格中
在这里插入图片描述

#学生信息存储
def Message(name_entry):
    #表格操作
    sheets = openpyxl.load_workbook(path0 + "Data.xlsx")  #打开“学生信息表”工作薄
    sheet1 = sheets[sheets.sheetnames[0]]  #获取Data工作薄里面的第一个表“学生信息表”
    max_row1 = sheet1.max_row  #获取第一个表格有数据最后一行的行数
    print("第几行:",max_row1)
    name = name_entry.get()  #利用get()方法获取Entry组件中输入的内容
    tkinter.messagebox.showinfo(title="提示",message="开始录入人脸信息!")  #消息方框
    image = str(max_row1)+".jpg"  #从表格获取行数,为照片进行编号
    get_photo(path + image)  #获取新学生的照片,保存到face文件夹里
    #填写学生信息,包括序号、姓名             
    sheet1.cell(max_row1 + 1,1).value = str(max_row1)  #学生序号,即照片编号
    print(type(sheet1.cell(max_row1 + 1,1).value))
    sheet1.cell(max_row1 + 1,2).value = name  #学生姓名
    sheets.save(path0 + "Data.xlsx")    
    print("注册成功,您的编号是"+ str(max_row1)+"号")
    tkinter.messagebox.showinfo(title="提示",message="完成注册!")  #消息方框

7. 返回按钮back_main()函数

#返回按钮,从当前界面(second_frame)返回主界面(main_frame)
def back_main(second_frame):
    second_frame.place_forget()  #隐藏second_frame框架
    main_frame.place(relwidth=1,relheight= 1)  #显示main_frame框架

五、备注

Data工作薄和完成程序链接
提取码:lyx4

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>