目录
变量初始化
在定义好GUI主体界面各模块后,需要对项目中用到的变量进行初始化;
代码实现如下,在类中的初始化模块,添加初始化变量代码:
import wx
class Face_recognition(wx.Frame):
def init (self):
self.frame = wx.Frame. init (self, parent=None, title="员工考勤系统",
size=(1000, 700))
self.initMenu()
self.init_data() # 此处添加初始化变量代码
然后在类中初始化菜单的方法initMenu() 后面添加实现变量初始化的方法init_data() ;
def init_data(self):
self.on = True # 注册标识变量
self.reg_msg = None # 注册时显示信息
self.del_msg = None # 删除时显示信息
self.search_msg = None # 查询时显示信息
self.command = None # 当前执行的命令
self.sql_name = 'my_Punch.db' # 数据库名字
self.recognize = True # 打卡
self.registration = False # 注册
self.search = True # 查询
self.c = None # 定义游标
self.conn = None # 连接名
self.user_id = [] # 用户ID
self.user_name = [] # 用户名
self.time_1 = [] # 上班时间
self.logcat_late = [] # 打卡时间
self.time_2 = [] # 下班时间
self.dur_time = [] # 持续时间
连接数据库
1. 数据库连接
在类中实现用于连接数据库的方法connect_sql ,在init_data()
""" 数据库连接
"""
import sqlite3
def connect_sql(self):
conn = sqlite3.connect(self.sql_name)
print("Opened database successfully!")
c = conn.cursor()
self.c = c
self.conn = conn
2. 创建数据表
在类中实现创建数据表的方法create_table ,在connect_sql() 下方写入如下代码:
"""
创建数据表
"""
def create_table(self):
c, conn = self.c, self.conn
c.execute('''CREATE TABLE if not exists attendance
(user_id CHAR(50) PRIMARY KEY NOT NULL,
user_name CHAR(50) NOT NULL,
sign_in_time Datetime,
checking_state CHAR(10) NOT NULL,
sign_out_time Datetime,
working_time float);''')
conn.commit()
3. 查询数据
在类中实现查询数据的方法Query_data ,在create_table() 下方写入如下代码:
"""
查询数据库中的数据
"""
def Query_data(self):
self.user_id = []
self.user_name = []
self.time_1 = []
self.logcat_late = []
self.time_2 = []
self.dur_time = []
self.connect_sql()
self.create_table()
c, conn = self.c, self.conn
c.execute("select * from attendance")
# print(c.fetchall())
for i in c.fetchall():
self.user_id.append(i[0])
self.user_name.append(i[1])
if i[2] == None:
self.time_1.append('None')
else:
self.time_1.append(i[2])
self.logcat_late.append(i[3])
if i[4] == None:
self.time_2.append('None')
else:
self.time_2.append(i[4])
if i[5] == None:
self.dur_time.append('None')
else:
self.dur_time.append(i[5])
self.c.close()
获取Access Token
向人脸识别API服务地址使用POST发送请求,必须在URL中带上参数access_token ,通过在百度智能云中创建应用得到的API Key和Secret Key生成(下方代码中ak和sk须修改为本人实际的密钥)。 在主类中实现代码如下:
"""
获取access_tokens
"""
def access_tokens(self):
# 此处的AK和SK,需要替换成自己的
ak = '********************'
sk = '********************'
# client_id 为官网获取的AK, client_secret 为官网获取的SK
host = 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id={}&client_secret={}'.format(
ak, sk)
response = requests.get(host)
if response:
return response.json()['access_token']
图片编码
请求的图片需经过Base64编码 ,图片的base64编码指将图片数据编码成一串字符串,使用该字符串代 替图像地址。可以首先得到图片的二进制,然后用Base64格式编码即可。在主类中实现代码如下:
"""
获取追踪到图片的BASE64格式并返回参数列表
"""
def imgdata(self, file1path, name=None, user_list=None):
import base64
f = open(r'%s' % file1path, 'rb')
pic = base64.b64encode(f.read())
f.close()
# 人脸搜索params
if name == 'face_search':
params = json.dumps({"image": str(pic, 'utf-8'),
"image_type": "BASE64", "group_id_list": "vipUser", "quality_control": "LOW",
"liveness_control": "NORMAL"})
# 人脸注册params
elif name == 'face_registration':
params = json.dumps({"image": str(pic, 'utf-8'), "image_type": "BASE64",
"group_id": "vipUser", "user_id": user_list[0], "user_info": user_list[1],
"quality_control": "LOW", "liveness_control": "NORMAL"})
# 人脸质量检测params
else:
params = json.dumps(
{"image": str(pic, 'utf-8'), "image_type": "BASE64", "face_type": "LIVE", "quality_control": "LOW"})
return params
百度AI接口调用
1. 人脸质量检测
需要判断一张图片中的人脸,是否符合后续识别或者对比的条件,在请求时在face_field 参数中请求 quality 。基于返回结果 quality 中,以下字段及对应阈值,进行质量检测的判断,以保证人脸质量符 合后续业务操作要求。在主类中实现代码如下:
'''
调用人脸质量检测API
'''
def picture_quality(self, file1path):
access_token = self.access_tokens()
assert access_token != None, 'access_token is None'
params = self.imgdata(file1path)
request_url = "https://aip.baidubce.com/rest/2.0/face/v3/detect"
request_url = request_url + "?access_token=" + access_token
headers = {'content-type': 'application/json'}
response = requests.post(request_url, data=params, headers=headers).json()
print(response)
if response['error_msg'] == 'SUCCESS':
score = response['result']['face_list'][0]['face_probability']
print(score, type(score))
if (type(score) == float) | (type(score) == int):
if score >= 0.8:
self.recognize = False
else:
self.recognize = True
print(score)
else:
self.recognize = True
print(response['error_msg'])
2. 人脸注册
向人脸库中添加人脸,用于后续的人脸对比,在主类中实现代码如下:
"""
调用人脸注册API
"""
def face_registration(self, file1path, user):
c, conn = self.c, self.conn
c.execute("select user_id from attendance where user_id='{}'".format(user[0]))
conn.commit()
l = c.fetchone()
if l == None:
c.execute("insert into attendance(user_id,user_name,checking_state) values(?,?,'未打卡')", (user[0], user[1]))
conn.commit()
access_token = self.access_tokens()
params = self.imgdata(file1path, 'face_registration', user)
request_url = "https://aip.baidubce.com/rest/2.0/face/v3/faceset/user/add"
request_url = request_url + "?access_token=" + access_token
headers = {'content-type': 'application/json'}
response = requests.post(request_url, data=params, headers=headers).json()
if response['error_msg'] == 'SUCCESS':
self.registration = True
print("注册成功")
self.reg_msg = "注册成功"
self.on = False
elif response['error_msg'] == 'face already exist':
print('您已经注册过了!')
self.registration = True
self.reg_msg = '您已经注册过了!'
self.on = False
else:
self.reg_msg = '您已经注册过了!'
self.on = False
self.c.close()
3. 人脸搜索
也称为1:N识别,在指定人脸集合中,找到最相似的人脸,用于识别后记录此人打卡信息,在主类中实 现代码如下:
"""
调用人脸搜索API
"""
def face_search(self, file1path):
c, conn = self.c, self.conn
access_token = self.access_tokens()
assert access_token != None, 'access_token is None'
params = self.imgdata(file1path, 'face_search')
request_url = "https://aip.baidubce.com/rest/2.0/face/v3/search"
request_url = request_url + "?access_token=" + access_token
headers = {'content-type': 'application/json'}
response = requests.post(request_url, data=params, headers=headers).json()
if response['error_msg'] == 'SUCCESS':
self.search = False
user_id = response['result']['user_list'][0]['user_id']
times = time.time()
this_time = time.localtime(times)
punch_time = "{}-{}-{} {}:{}:{}".format(this_time.tm_year, this_time.tm_mon, this_time.tm_mday,
this_time.tm_hour, this_time.tm_min, this_time.tm_sec)
c.execute("select checking_state from attendance where user_id='{}'".format(user_id))
if c.fetchone()[0] == '未打卡':
print('上班打卡')
if this_time.tm_hour >= 8:
stats = '是'
self.search_msg = '上班打卡成功!您迟到了!'
print('迟到了')
else:
stats = '否'
self.search_msg = '上班打卡成功!'
c.execute("update attendance set sign_in_time='{}', checking_state ='{}' where user_id='{}' ".format(
punch_time, stats, user_id))
conn.commit()
else:
c.execute("select sign_in_time from attendance where user_id='{}'".format(user_id))
start = time.mktime(time.strptime(c.fetchone()[0], "%Y-%m-%d %H:%M:%S"))
during_time = round((times - start) / 60 / 60, 2)
c.execute(
"update attendance set sign_out_time='{}', working_time='{}' where user_id='{}'".format(punch_time,
during_time,
user_id))
conn.commit()
print('下班打卡')
self.search_msg = '下班打卡成功,今日上班时长为{}小时'.format(during_time)
self.on = False
elif response['error_msg'] == 'match user is not found':
self.search = False
self.search_msg = '请您先进行注册!'
print('请您先进行注册!')
self.on = False
else:
self.search = False
self.search_msg = response['error_msg']
self.on = False
self.c.close()
4. 人脸删除
用于删除指定用户的某张人脸,指定用户可以上传20张以内的人脸图片,在主类中实现代码如下:
'''
获取用户人脸列表并删除
'''
def face_getlist(self, user_id):
self.connect_sql()
self.create_table()
c, conn = self.c, self.conn
c.execute("DELETE FROM attendance where user_id='{}'".format(user_id))
conn.commit()
access_token = self.access_tokens()
assert access_token != None, 'access_token is None'
# 人脸删除
def face_delete(user_idx, face_token):
request_url = "https://aip.baidubce.com/rest/2.0/face/v3/faceset/face/delete"
params = json.dumps({"user_id": user_idx, "group_id": "vipUser", "face_token": face_token})
request_url = request_url + "?access_token=" + access_token
headers = {'content-type': 'application/json'}
response = requests.post(request_url, data=params, headers=headers).json()
if response['error_code'] == 0:
del_msg = "删除成功"
else:
del_msg = response['error_msg']
print(del_msg)
self.del_msg = del_msg
# 获取用户的face_token
request_url = "https://aip.baidubce.com/rest/2.0/face/v3/faceset/face/getlist"
params = json.dumps({"user_id": user_id, "group_id": "vipUser"})
request_url = request_url + "?access_token=" + access_token
headers = {'content-type': 'application/json'}
response = requests.post(request_url, data=params, headers=headers).json()
if response['error_msg'] == 'SUCCESS':
for i in response['result']['face_list']:
face_token = i['face_token']
face_delete(user_id, face_token)
else:
self.del_msg = response['error_msg']
print(response['error_msg'])
self.c.close()
人脸跟踪
人脸跟踪用于检测图片中的人脸并标记出位置信息,此模块由OpenCV实现,在主类中实现代码如下:
"""
使用OpenCV实现人脸追踪
"""
def face_tracking(self):
self.connect_sql()
self.create_table()
if self.command == 'registration':
user, ids, name = [], self.txtRegisterNum.GetValue(), self.txtName.GetValue()
user.extend([ids, name])
cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
# 设置显示大小
cap.set(3, 450)
cap.set(4, 450)
# 创建人脸检测器(快速Harr)
face_cascade = cv2.CascadeClassifier(".\\haarcascade_frontalface_alt2.xml")
start_time = time.time()
i = 1
while True:
print(i)
i = i + 1
ret, frame = cap.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
ret, buf = cv2.imencode(".jpg", gray)
img_bin = Image.fromarray(np.uint8(buf)).tobytes()
faces = face_cascade.detectMultiScale(gray)
max_face = 0
value_x = 0
# 追踪到人脸
last_time = time.time()
time_interval = last_time - start_time
if (len(faces) > 0) & (time_interval >= 3):
for (x, y, w, h) in faces:
if self.recognize == True:
roiImg = frame[y:y + w + 30, x:x + h]
cv2.imwrite('.//1.jpg', roiImg)
cv2.rectangle(frame, (x, y), (x + h, y + w), (0, 255, 0), 2)
result = (x, y, w, h)
x = result[0]
y = result[1]
# 判断是否需要人脸质量检测
if self.recognize == True:
self.picture_quality('.//1.jpg')
else:
if self.command == 'search':
if self.search == True:
self.face_search('.//1.jpg')
elif self.command == 'registration':
if self.registration == False:
self.face_registration('.//1.jpg', user)
if self.command == 'search':
height, width = frame.shape[:2]
image1 = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
pic = wx.Bitmap.FromBuffer(width, height, image1)
self.bmpSign.SetBitmap(pic)
if (self.command == 'search') & (self.on == False):
wx.MessageBox(self.search_msg, 'message', wx.OK | wx.ICON_INFORMATION)
self.c.close()
self.init_data()
self.bmpSign.SetBitmap(wx.Bitmap(self.imageBackgroud))
break
if self.command == 'registration':
height, width = frame.shape[:2]
image1 = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
pic = wx.Bitmap.FromBuffer(width, height, image1)
self.bmpRegister.SetBitmap(pic)
if (self.command == 'registration') & (self.on == False):
wx.MessageBox(self.reg_msg, 'message', wx.OK | wx.ICON_INFORMATION)
self.c.close()
self.init_data()
self.bmpRegister.SetBitmap(wx.Bitmap(self.imageBackgroud1))
break
cap.release()
cv2.destroyAllWindows()
self.btnSign.Show()
至此,所有模块实现完毕!
功能验证
1.注册人脸
点击人脸注册菜单,输入ID号和姓名,点击【确认】按钮,启动摄像头,识别并注册人脸,弹出【注册 成功】提示!
点击【确认】按钮,退出注册!
2. 打卡
点击员工菜单,点击【打卡】按钮,启动摄像头,识别并完成打卡任务,弹出【上班打卡成功】提示!
3. 查看打卡信息
点击【查看员工打卡信息】菜单,点击【查询】按钮,在工作区显示打卡记录信息,如图所示!
4. 人脸删除
点击【人脸删除】菜单,在文本框中输入待删除员工的id,如上述步骤中注册的【001】,点击【确 认删除】按钮,从人脸库中删除该用户信息,如图所示,弹出【删除成功】对话框!
点击【确认】保存退出!
总结
本节课我们学习了变量初始化,连接数据库,获取Access Token,图片编码,百度AI接口调用,人脸跟踪和项目功能验证的相关内容。至此人脸识别打卡项目(1-7)也到这里结束了。回首这段时光,来时是重重的行囊,走时是满满的收获。感谢大家一路陪伴。
如果有需要全部代码的可以私信我,我也会第一时间为排忧解难。