《百度AI人脸识别与检测》专栏为项目专栏,从零到一,从无到有开发一个学生人脸识别签到系统;主要用到的技术有百度开放平台中的人脸检测、人脸识别、Python图形界面开发PyQt5、线程的管理、以及通过python调用百度接口实现人脸检测、百度开放平台中人脸检测技术文档的理解等,由浅入深、由局部到整体的一个项目学习过程,如果你想对人脸识别感兴趣,对python的图形界面设计感兴趣,可以订阅本专栏,因为对你可能有帮助哦!
前文参考:
百度AI人脸识别与检测一:学生人脸识别签到系统简介及百度AI开放平台账号注册和人脸实例应用创建
百度AI人脸识别与检测二:学生人脸识别打卡签到系统主界面功能需求和设计以及通过Python实现界面运行
百度AI人脸识别与检测三:学生人脸识别打卡签到系统通过OpenCV实现电脑摄像头数据在Label控件上的实时显示
百度AI人脸识别与检测四:学生人脸识别打卡签到系统之百度AI人脸检测及相应程序异常处理
百度AI人脸识别与检测五:学生人脸识别打卡签到系统之百度AI人脸识别
百度AI人脸识别与检测六:学生人脸识别打卡签到系统之班级的增删查
百度AI人脸识别与检测七:学生人脸识别打卡签到系统之学生人脸信息的添加
上次博客,林君学长讲解了如何利用百度AI开放平台的人脸识别中用户注册模块来完成我们打卡签到系统中的学生人脸及有关信息的录入,本次博客的主要内容在上次内容的基础之上,完成学生人脸信息的删除。下面一起阅读内容进行学习吧!
百度AI人脸识别与检测八:学生人脸识别打卡签到系统之删除学生人脸及信息
一、设计学生信息删除窗口
对于学生信息的删除窗口,如同上次博客所对于学生增加的窗口一样进行需求分析,在合适的需求之下,完成对应控件的布局,实现我们学生人脸及相关信息的删除。在学生人脸识别打卡签到系统中,面对某一届学生的毕业,在系统中需要删除学生的有关信息,因此需要此功能!
对于学生的删除,我们需要通过什么参数,然后删除学生的一些什么信息?首先可以明确的是,得找到需要删除学生的班级,然后通过学生学号进行对应信息的删除。所以,对于学生信息的删除,需要的就是两个删除,一个是班级名称,一个是学生学号,有着两个参数,就可以完成学生人脸及有关信息的删除,下面一起来实现该局部模块功能吧!
1、设计删除学生人脸信息界面
(1)、在pycharm中打开pyqt5designer.exe窗口设计软件,同样选择Dialog其中的任意一个,来进行删除界面UI的设计
(2)根据需求模块,在删除界面窗口中添加列表班级选择控件和学生列表展示控件,然后点击确认进行删除,如下图所示:
设计以上布局之后,点击保存到项目中,命名为del_student.ui
(3)在pycharm的终端,将保存的ui文件转为可以运行执行的py文件,命名为del_student.py
pyuic5 del_student.ui -o del_student.py
2、对学生人脸信息进行实例化
(1)、在项目中创建名为del_student_window.py的实例化“学生人脸信息删除”窗口文件,该文件中的类主要来实现学生人脸信息的相关访问信息的获取及功能实现,并将如下代码写进文件中:
from PyQt5.QtWidgets import QDialog
from del_student import Ui_Dialog
class del_student_window(Ui_Dialog,QDialog):
def __init__(self,list,token,parent=None):
super(del_student_window,self).__init__(parent)
self.setupUi(self)
self.access_token = token#定义全局变量,接收来自主界面传递过来的token,访问令牌
(2)、在del_student_window.py文件末尾添加将班级列表显示在下拉框中的函数
from PyQt5.QtWidgets import QDialog
from del_student import Ui_Dialog
class del_student_window(Ui_Dialog,QDialog):
def __init__(self,list,token,parent=None):
super(del_student_window,self).__init__(parent)
self.setupUi(self)
self.show_class(list)#在删除页面弹出时候,直接调用班级显示函数,进行班级列表在下拉框中的显示
self.access_token = token#定义全局变量,接收来自主界面传递过来的token,访问令牌
# 显示班级信息在下拉框
def show_class(self, list):
self.comboBox.clear() #清楚下拉框的内容,放一次下一次进入后重叠
for i in list:
self.comboBox.addItem(i)
位置如下所示:
3、主界面与删除界面间的跳转
(1)、主界面function_window.py文件中导入删除界面窗口文件
from del_student_window import del_student_window
(2)、在function_window.py文件内容末尾添加删除学生人脸及有关信息的方法,并将获取到的班级列表传递给代码如下所示:
#删除学生信息
def del_student(self):
list = self.get_class()#获取班级列表
if list['error_msg'] == 'SUCCESS':
window = del_student_window(list['result']['group_id_list'], self.access_token, self)
# 新创建窗口,通过exec()函数一直在执行,窗口不进行关闭
window_status = window.exec_()
# 判断
# print(window_status)
if window_status != 1:
return
(3)、为“学生信息管理”菜单栏中的删除学生按钮进行事件绑定,绑定到方法del_student
self.actiondelStu.triggered.connect(self.del_student)#删除学生人脸信息事件绑定
(4)、运行程序,进行主界面与学生删除界面之间的跳转
可以看到,现在已经基本完成跳转,并且实现班级的显示!下面开始正式步入学生信息删除的步骤。
二、阅读百度AI之人脸删除API文档
1、文档详阅链接
2、请求说明
(1)、Python代码的请求格式为
request_url = "https://aip.baidubce.com/rest/2.0/face/v3/faceset/face/delete"
params = {
"user_id":"用户ID",
"group_id":"用户组ID",
"face_token":"访问令牌"
}
access_token = self.access_token
request_url = request_url + "?access_token=" + access_token
headers = {'content-type': 'application/json'}
response = requests.post(request_url, data=params, headers=headers)
if response:
data = response.json()
请求参数的说明在上面的访问格式代码中学长已经做出标注,分别为用户ID(学号)、用户组ID(班级名称)、以及访问令牌
(2)、具体参考下图
3、返回参数
(1)、返回参数实例如下图所示:
// 删除成功
{
"error_code": 0,
"log_id": 73473737,
}
// 删除发生错误
{
"error_code": 223106,
"log_id": 1382953199,
"error_msg": "face is not exist"
}
返回的“error_code”可作为返回判断,当error_code=0的时候,表示删除成功,但当error_code=其他数的时候,删除错误。
通过对以上API文档的阅读,下面在打开签到系统中完成该部分的实现吧!
三、实现签到系统中学生人脸及信息删除
1、完成班级中,学生列表的显示
(1)、在del_student_window.py文件中,添加方法,完成对下拉框中选中的班级进行班级中学生的展示,目前只展示学号,对于其他的,可以通过获取其他信息展示在上面,具体代码如下所示:
import requests
from PyQt5.QtWidgets import QDialog, QMessageBox
from del_student import Ui_Dialog
class del_student_window(Ui_Dialog,QDialog):
def __init__(self,list,token,parent=None):
super(del_student_window,self).__init__(parent)
self.setupUi(self)
self.show_class(list)#在删除页面弹出时候,直接调用班级显示函数,进行班级列表在下拉框中的显示
self.access_token = token#定义全局变量,接收来自主界面传递过来的token,访问令牌
self.pushButton_2.clicked.connect(self.close_window)#取消删除按钮事件绑定
self.comboBox.activated.connect(self.choose_group_student)#对下拉框发生选择的时候进行事件绑定
self.pushButton.clicked.connect(self.get_data)#对确定删除按钮进行事件绑定
# 显示班级信息在下拉框
def show_class(self, list):
self.comboBox.clear() #清楚下拉框的内容,放一次下一次进入后重叠
for i in list:
self.comboBox.addItem(i)
#取消删除
def close_window(self):
self.close()
#学生列表展示
def show_student_list(self,list):
self.listWidget.clear()#清楚文本框的内容
if list['result']['user_id_list'] == []:
self.listWidget.addItem("该班级中暂无学生!")
for l in list['result']['user_id_list']:
self.listWidget.addItem(l)#将获取到的学生列表显示在文本框中
# 获取学生列表
def get_student_list(self,group):
request_url = "https://aip.baidubce.com/rest/2.0/face/v3/faceset/group/getusers"
params = {
"group_id": group
}
access_token = self.access_token
request_url = request_url + "?access_token=" + access_token
headers = {'content-type': 'application/json'}
response = requests.post(request_url, data=params, headers=headers)
if response:
return response.json()
#获取选中班级中的学生的事件绑定
def choose_group_student(self):
class_name = self.comboBox.currentText()
student_list=self.get_student_list(class_name)
self.show_student_list(student_list)
#获取数据
def get_data(self):
#在删除界面上的文本框中,获取我们选择的班级和学号进行后面的删除
try:
self.class_name=self.comboBox.currentText()#获取下拉框中的班级名称
self.student_no = self.listWidget.currentItem().text()#获取学生列表中的学生
if self.student_no=="该班级中暂无学生!":
QMessageBox.about(self, "提示", "请确认班级和学生!")
return
#关闭对话框
self.accept()
except:
QMessageBox.about(self,"提示","请确认班级和学生!")
2、完成学生人脸及信息删除
(1)、在function_window.py文件中,找到之前创建的del_student删除学生方法,进行删除学生代码的添加,具体代码如下所示:
#删除学生信息
def del_student(self):
list = self.get_class()#获取班级列表
if list['error_msg'] == 'SUCCESS':
window = del_student_window(list['result']['group_id_list'], self.access_token, self)
# 新创建窗口,通过exec()函数一直在执行,窗口不进行关闭
window_status = window.exec_()
# 判断
if window_status != 1:
return
class_name = window.class_name
student_list = window.get_student_list(class_name)
if student_list['error_msg'] == 'SUCCESS':
student_no = window.student_no
if student_no == "":
return
for i in student_list['result']['user_id_list']:
if student_no == i:
face_list = self.user_face_list(class_name, student_no)
if face_list['error_msg'] == 'SUCCESS':
for i in face_list['result']['face_list']:
self.del_face_token(class_name, student_no, i['face_token'])
else:
return
else:
return
else:
return
else:
return
#通过API访问规则,对学生人脸及有关信息进行删除
def del_face_token(self,class_name,student_no,facetoken):
request_url = "https://aip.baidubce.com/rest/2.0/face/v3/faceset/face/delete"
params = {
"user_id":student_no,
"group_id":class_name,
"face_token":facetoken
}
access_token = self.access_token
request_url = request_url + "?access_token=" + access_token
headers = {'content-type': 'application/json'}
response = requests.post(request_url, data=params, headers=headers)
if response:
data = response.json()
if data['error_code'] == 0:
QMessageBox.about(self,"删除状态","学生人脸及信息删除成功!")
else:
QMessageBox.about(self,"删除状态","学生人脸及信息删除失败!")
# 获取用户人脸列表
def user_face_list(self, group, user):
request_url = "https://aip.baidubce.com/rest/2.0/face/v3/faceset/face/getlist"
params = {
"user_id": user,
"group_id": group
}
access_token = self.access_token
request_url = request_url + "?access_token=" + access_token
headers = {'content-type': 'application/json'}
response = requests.post(request_url, data=params, headers=headers)
if response:
return response.json()
3、运行实例展示
(1)、运行程序,删除学生信息,如下所示:
(2)、删除成功通知
(3)、百度AI开放平台查看是否删除成功
从上面可以看出,学生“chenyiyue”已经被成功删除,因此该模块的功能完成!
4、项目代码修改
del_student_window.py文件中的代码在上面已经给出,后面基本没有做过多的修改,而对于function_window.py文件中的代码,修改完成后最终代码如下所示:
import base64
import cv2
import requests
from PyQt5.QtCore import QTimer
from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import QMainWindow, QMessageBox, QInputDialog
from cameraVideo import camera
from mainWindow import Ui_MainWindow
from detect import detect_thread
from add_student_window import add_student_window
from del_student_window import del_student_window
class function_window(Ui_MainWindow,QMainWindow):
'''
初始化函数
'''
def __init__(self):
super(function_window, self).__init__()
self.setupUi(self)
self.label.setScaledContents(True)#设置图像自适应label显示框
self.pushButton.clicked.connect(self.open_Sign)#打开签到事件绑定
self.pushButton_2.clicked.connect(self.close_Sign)#关闭签到事件绑定
self.actionaddclass.triggered.connect(self.add_class)#添加班级按钮事件绑定
self.actionfindclass.triggered.connect(self.display_class)#查询班级按钮事件绑定
self.actiondelclass.triggered.connect(self.delete_calss)#删除班级按钮事件绑定
self.actionaddStu.triggered.connect(self.add_student)#增加学生人脸信息事件绑定
self.actiondelStu.triggered.connect(self.del_student)#删除学生人脸信息事件绑定
self.access_token=self.get_accessToken()#获取Access_token访问令牌,并复制为全局变量
self.start_state=True
'''
打开签到
'''
def open_Sign(self):
if self.start_state==True:
# 启动摄像头
self.cameravideo = camera()
# 启动定时器进行定时,每隔多长时间进行一次获取摄像头数据进行显示
self.timeshow = QTimer(self)
self.timeshow.start(10)
# 每隔10毫秒产生一个信号timeout
self.timeshow.timeout.connect(self.show_cameradata)
self.detect = detect_thread(self.access_token) # 创建线程
self.detect.start() # 启动线程
# 签到500毫秒获取一次,用来获取检测的画面
self.faceshow = QTimer(self)
self.faceshow.start(500)
self.faceshow.timeout.connect(self.get_cameradata)
self.detect.transmit_data.connect(self.get_data)
self.detect.transmit_data1.connect(self.get_seach_data)
self.start_state=False
else:
QMessageBox.about(self, "提示", "正在检测,请先关闭!")
'''
关闭签到
'''
def close_Sign(self):
if self.start_state==False:
self.faceshow.stop() # 计时器停止
self.detect.ok = False # 停止run函数运行
self.detect.quit() # 关闭线程
# 关闭定时器,不再获取摄像头的数据
self.timeshow.stop()
self.timeshow.timeout.disconnect(self.show_cameradata)
# 关闭摄像头
self.cameravideo.colse_camera()
self.start_state=True
# 判断定时器是否关闭,关闭,则显示为自己设定的图像
if self.timeshow.isActive() == False:
self.label.setPixmap(QPixmap("image/1.jpg"))
self.plainTextEdit_2.clear()
else:
QMessageBox.about(self, "警告", "关闭失败,存在部分没有关闭成功!")
else:
QMessageBox.about(self, "提示", "请先开始检测!")
#获取人脸检测数据并显示到文本框中
def get_data(self,data):
if data['error_code']!=0:
self.plainTextEdit_2.setPlainText(data['error_msg'])
return
elif data['error_msg'] == 'SUCCESS':
self.plainTextEdit_2.clear()
# 在data字典中键为result对应的值才是返回的检测结果
face_num = data['result']['face_num']
# print(face_num)
if face_num == 0:
self.plainTextEdit_2.setPlainText("当前没有人或人脸出现!")
return
else:
self.plainTextEdit_2.clear()
self.plainTextEdit_2.appendPlainText("检测到人脸!")
self.plainTextEdit_2.appendPlainText("——————————————")
# 人脸信息获取['result']['face_list']是列表,每个数据就是一个人脸信息,需要取出每个列表信息(0-i)
for i in range(face_num):
age = data['result']['face_list'][i]['age'] # 年龄
# print(age)
beauty = data['result']['face_list'][i]['beauty'] # 美观度
gender = data['result']['face_list'][i]['gender']['type'] # 性别
expression = data['result']['face_list'][i]['expression']['type']
face_shape = data['result']['face_list'][i]['face_shape']['type'] # 脸型
glasses = data['result']['face_list'][i]['glasses']['type'] # 是否戴眼镜
emotion = data['result']['face_list'][i]['emotion']['type'] # 情绪
mask = data['result']['face_list'][i]['mask']['type'] # 是否戴口罩
# 往窗口中添加文本,参数就是需要的文本信息
# print(age,gender,expression,beauty,face_shape,emotion,glasses,mask)
self.plainTextEdit_2.appendPlainText("第" + str(i + 1) + "个学生人脸信息:")
self.plainTextEdit_2.appendPlainText("——————————————")
self.plainTextEdit_2.appendPlainText("年龄:" + str(age))
if gender == 'male':
gender = "男"
else:
gender = "女"
self.plainTextEdit_2.appendPlainText("性别:" + str(gender))
self.plainTextEdit_2.appendPlainText("表情:" + str(expression))
self.plainTextEdit_2.appendPlainText("颜值分数:" + str(beauty))
self.plainTextEdit_2.appendPlainText("脸型:" + str(face_shape))
self.plainTextEdit_2.appendPlainText("情绪:" + str(emotion))
if glasses == "none":
glasses="否"
elif glasses == "common":
glasses="是:普通眼镜"
else:
glasses="是:太阳镜"
self.plainTextEdit_2.appendPlainText("是否佩戴眼镜:" + str(glasses))
if mask == 0:
mask = "否"
else:
mask = "是"
self.plainTextEdit_2.appendPlainText("是否佩戴口罩:" + str(mask))
self.plainTextEdit_2.appendPlainText("——————————————")
else:
print("人脸获取失败!")
'''
获取图像,并转换为base64格式
'''
def get_cameradata(self):
camera_data1 = self.cameravideo.read_camera()
# 把摄像头画面转化为一张图片,然后设置编码为base64编码
_, enc = cv2.imencode('.jpg', camera_data1)
base64_image = base64.b64encode(enc.tobytes())
#产生信号,传递数据
self.detect.get_imgdata(base64_image)
'''
摄像头数据显示
'''
def show_cameradata(self):
#获取摄像头数据
pic=self.cameravideo.camera_to_pic()
#在lebel框中显示数据、显示画面
self.label.setPixmap(pic)
'''
获取Access_token访问令牌
'''
def get_accessToken(self):
# client_id 为官网获取的AK, client_secret 为官网获取的SK
host = 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=TKGXdKC7WPWeADGHmFBN8xAr&client_secret=lsr1tAuxv3tRGmOgZTGgNyri667dfKGg'
# 进行网络请求,使用get函数
response = requests.get(host)
if response:
data = response.json()
self.access_token = data['access_token']
return self.access_token
else:
QMessageBox(self,"提示","请检查网络连接!")
def get_seach_data(self,data):
self.plainTextEdit.setPlainText(data)
#添加班级
def add_class(self):
# 打开输入框,进行输入用户组
group, ret = QInputDialog.getText(self, "添加班级", "请输入班级名称(由数字、字母、下划线组成)")
if group == "":
print("取消添加班级")
else:
request_url = "https://aip.baidubce.com/rest/2.0/face/v3/faceset/group/add"
params = {
"group_id": group
}
access_token = self.access_token
request_url = request_url + "?access_token=" + access_token
headers = {'content-type': 'application/json'}
response = requests.post(request_url, data=params, headers=headers)
if response:
print(response.json())
message = response.json()
if message['error_code'] == 0:#根据规则,返回0则为班级添加成功
QMessageBox.about(self, "班级创建结果", "班级创建成功")
else:
QMessageBox.about(self, "班级创建结果", "班级创建失败")
#班级查询
def get_class(self):
request_url = "https://aip.baidubce.com/rest/2.0/face/v3/faceset/group/getlist"
params = {
"start":0,
"length":100
}
access_token = self.access_token
request_url = request_url + "?access_token=" + access_token
headers = {'content-type': 'application/json'}
response = requests.post(request_url, data=params, headers=headers)
if response:
return response.json()
#将查询到的结果显示在MessageBOX框上面
def display_class(self):
list=self.get_class()
str=''
for i in list['result']['group_id_list']:
str=str+'\n'+i
QMessageBox.about(self,"班级列表",str)
#班级删除
def delete_calss(self):
#打开输入框,进行输入用户组
list = self.get_class()#首先获取用户组信息
group,ret=QInputDialog.getText(self, "存在的班级", "班级信息"+str(list['result']['group_id_list']))
if group == "":
print("取消删除班级")
else:
request_url = "https://aip.baidubce.com/rest/2.0/face/v3/faceset/group/delete"
params = {
"group_id": group#要删除用户组的id
}
access_token = self.access_token
request_url = request_url + "?access_token=" + access_token
headers = {'content-type': 'application/json'}
response = requests.post(request_url, data=params, headers=headers)
if response:
print(response.json())
message = response.json()
if message['error_code'] == 0:
QMessageBox.about(self, "班级删除结果", "班级删除成功")
else:
QMessageBox.about(self, "班级删除结果", "班级删除失败")
#增加学生信息
def add_student(self):
'''
人脸注册
'''
list=self.get_class()#获取班级,将班级信息传递到我们新建的界面之中
# 创建一个窗口,进行用户信息录入
window = add_student_window(list['result']['group_id_list'],self)#将获取到的班级传递到新的界面,后续有用
#新创建窗口,通过exec()函数一直在执行,窗口不进行关闭
window_status=window.exec_()
#判断
if window_status !=1:
return
base64_image = window.base64_image
# 参数请求中,需要获取人脸编码,添加的组的id,添加的用户,新用户id信息
request_url = "https://aip.baidubce.com/rest/2.0/face/v3/faceset/user/add"
params = {
"image": base64_image, # 人脸图片
"image_type": "BASE64", # 图片编码格式
"group_id": window.class_id, # 班级名称
"user_id": window.student_id, # 学生学号
"user_info": window.student_name# 学生姓名
}
access_token = self.access_token
request_url = request_url + "?access_token=" + access_token
headers = {'content-type': 'application/json'}
response = requests.post(request_url, data=params, headers=headers)
if response:
data = response.json()
if data['error_code'] == 0:
QMessageBox.about(self, "增加结果", "学生增加成功!")
else:
QMessageBox.about(self, "增加结果", "学生增加失败!")
#删除学生信息
def del_student(self):
list = self.get_class()#获取班级列表
if list['error_msg'] == 'SUCCESS':
window = del_student_window(list['result']['group_id_list'], self.access_token, self)
# 新创建窗口,通过exec()函数一直在执行,窗口不进行关闭
window_status = window.exec_()
# 判断
if window_status != 1:
return
class_name = window.class_name
student_list = window.get_student_list(class_name)
if student_list['error_msg'] == 'SUCCESS':
student_no = window.student_no
if student_no == "":
return
for i in student_list['result']['user_id_list']:
if student_no == i:
face_list = self.user_face_list(class_name, student_no)
if face_list['error_msg'] == 'SUCCESS':
for i in face_list['result']['face_list']:
self.del_face_token(class_name, student_no, i['face_token'])
else:
return
else:
return
else:
return
else:
return
#通过API访问规则,对学生人脸及有关信息进行删除
def del_face_token(self,class_name,student_no,facetoken):
request_url = "https://aip.baidubce.com/rest/2.0/face/v3/faceset/face/delete"
params = {
"user_id":student_no,
"group_id":class_name,
"face_token":facetoken
}
access_token = self.access_token
request_url = request_url + "?access_token=" + access_token
headers = {'content-type': 'application/json'}
response = requests.post(request_url, data=params, headers=headers)
if response:
data = response.json()
if data['error_code'] == 0:
QMessageBox.about(self,"删除状态","学生人脸及信息删除成功!")
else:
QMessageBox.about(self,"删除状态","学生人脸及信息删除失败!")
# 获取用户人脸列表
def user_face_list(self, group, user):
request_url = "https://aip.baidubce.com/rest/2.0/face/v3/faceset/face/getlist"
params = {
"user_id": user,
"group_id": group
}
access_token = self.access_token
request_url = request_url + "?access_token=" + access_token
headers = {'content-type': 'application/json'}
response = requests.post(request_url, data=params, headers=headers)
if response:
return response.json()
本次博客的内容到这里就完结了,希望通过对于百度AI的文档阅读,可以帮助小伙伴更好的理解和实现学生人脸识别打卡签到系统中的学生人脸及有关信息的删除,在本次的删除中,运用到了API文档中的学生信息查询和搜素的API文档,因此,下一章的内容将不再介绍对API文档的阅读,直接开始我们的学生信息查询模块,搜索、展示一体化,小伙伴们记得准时订阅收获哦!
以上就是本次博客的全部内容,遇到问题的小伙伴记得留言评论,学长看到会为大家进行解答的,这个学长不太冷!
工作单位培训的第三天,让自己找到了在学校上课的感觉,相同的是,对于某些老师的授课具有出奇的困意,而对于某些老师的授课又具有非常的兴趣。再听课,早已经找不到在学校的状态已!
陈一月的又一天编程岁月^ _ ^