百度AI人脸识别与检测五:学生人脸识别打卡签到系统之百度AI人脸识别

《百度AI人脸识别与检测》专栏为项目专栏,从零到一,从无到有开发一个学生人脸识别签到系统;主要用到的技术有百度开放平台中的人脸检测、人脸识别、Python图形界面开发PyQt5、线程的管理、以及通过python调用百度接口实现人脸检测、百度开放平台中人脸检测技术文档的理解等,由浅入深、由局部到整体的一个项目学习过程,如果你想对人脸识别感兴趣,对python的图形界面设计感兴趣,可以订阅本专栏,因为对你可能有帮助哦!

前文参考:

百度AI人脸识别与检测一:学生人脸识别签到系统简介及百度AI开放平台账号注册和人脸实例应用创建
百度AI人脸识别与检测二:学生人脸识别打卡签到系统主界面功能需求和设计以及通过Python实现界面运行
百度AI人脸识别与检测三:学生人脸识别打卡签到系统通过OpenCV实现电脑摄像头数据在Label控件上的实时显示
百度AI人脸识别与检测四:学生人脸识别打卡签到系统之百度AI人脸检测及相应程序异常处理

最近博客发布于6个月之前,这半年时间,学长也接收到很多小伙伴对《百度AI人脸识别与检测》专栏的催更,但也只做了简单的回应。在这脱更的半年时间中,学长完成了自己的毕业设计、毕业论文,同时拿到了自己工作单位的offer,成为了一名简简单单的程序员;拿到了自己的驾驶证,成为了新手司机中的一份子;拿到了属于自己大学四年的毕业证和学位证,成为了广大校友中的一名新人。从学校到职场,从学生到校友,是林君学长这脱更6个月的变化。自己的大学四年,感谢每一位教育过自己的老师,同时也感谢物联一班的每一位同学、朋友。但总之,学长再次开始了属于自己的创作之旅。祝愿我们每一位小伙伴都能在学习中进步和成长,不只是简单的应付作业哦!



上次博客我们介绍了百度AI的人脸检测,并通过界面实现了基本的人脸检测,本次博客林君学长将带大家了解、并实现基于百度AI的人脸识别。人脸识别和人脸检测有本质上的区别,人脸检测只是将图像或者视频中的人脸进行一个简单的检测,包括面部表情、颜值分数、是否佩戴眼镜等等;而人脸识别是指将图像或者视频的人脸进行检测,然后进行识别,不仅检测到这个人,还要识别出这个人是谁,叫什么名字,对应的了解到这个人的一系列信息。因此,人脸识别是在人脸检测到的基础上,通过对应的特征对比,来判断数据库中的人脸特征是否有与检测的到的人脸特征一致,如果一致,找到此人;如果不一致,查无此人!


一、百度AI人脸识别API接口

百度AI人脸识别API接口是本地代码与百度云服务器进行连接的访问规则,本次博客需要对百度人脸识别进行访问,因此需要查看对应的API接口规则,根据规则编写访问接口的Python代码。而对于对应接口地址,在上次博客中已经介绍如何查看,本次博客需要用到的人脸识别主要用的是其中的人脸搜索接口。
在这里插入图片描述

1、创建用户脸部信息组

最新的百度AI开放平台好像要进行实名认证,然后才能领取免费的人脸识别模块,打开人脸识别模块的功能,所以小伙伴记得去实名认证,然后免费领取一下
在这里插入图片描述

既然是人脸搜索,对应的应该有一个用户的脸部信息库,但由于初次运用,需要我们手动录取信息,在之后的项目中,可以通过软件自动添加人脸信息或者更新人脸信息,便不再需要在百度AI平台上进行手动添加。由于初次进行识别,我们需要穿件用户组合人脸信息,具体步骤如下所示:
(1)、打开控制台,找到人脸识别版块后选择管理应用,上次博客我们创建了应用实例。
在这里插入图片描述
(2)、在学生人脸打开签到系统实例中,点击查看人脸库。
在这里插入图片描述
(3)、点击新建组,ID我们取为class1,寓意为第一个班级,然后点击确定。
在这里插入图片描述
通过以上步骤,我们的班级就创建好了!接下来,我们为班级中添加学生吧!

2、创建用户脸部信息

班级创建完成,但是目前班级中没有成员,需要我们手动添加学生的脸部信息
(1)点击刚刚创建好的class1的用户组,进入到用户组里面添加用户。
在这里插入图片描述
(2)、点击新建用户。填入用户的名字(拼音或者英文名字,暂不支持中文),然后选择一张该用户(学生)的照片上传到用户组中,如下所示:
在这里插入图片描述

在这里插入图片描述
(3)、多次循环操作,便为班级添加好了学生,学长只添加了自己的,因此列表只有一项。

在这里插入图片描述
这样,我们班级一的人脸数据库便创建成功,下面便可以通过API接口进行对应代码的编写了!

3、人脸搜索API请求文档说明

在编写相关人脸识别的代码之前,我们首先需要了解如何访问百度AI开放平台中人脸识别模块中的人脸搜索功能。官方给了对于的API文档说明,链接如下:
人脸搜索API官方请求文档说明
在API文档中,我们首先得找请求说明,该部分有请求代码格式,以及请求参数说明,具体如下步骤。
(1)、请求格式标准代码Python

# encoding:utf-8
import requests
'''
人脸搜索
'''
request_url = "https://aip.baidubce.com/rest/2.0/face/v3/search"
params = "{\"image\":\"027d8308a2ec665acb1bdf63e513bcb9\",\"image_type\":\"FACE_TOKEN\",\"group_id_list\":\"group_repeat,group_233\",\"quality_control\":\"LOW\",\"liveness_control\":\"NORMAL\"}"
access_token = '[调用鉴权接口获取的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())

(2)请求参数说明

  • image:需要进行人脸识别的图像。
  • image_type:图像的格式,这里的格式我们上次博客设置的base64,因此本次的格式依旧如此。
  • FACE_TOKEN:调用鉴权接口获取的token,通过AK和SK获取的token
  • group_id_list:需要在那个用户组列表中进行人脸识别对比

重要的是以上四个,后面的参数请通过API官方文档自行了解,下面给出后面参数的解释截图:
在这里插入图片描述

4、人脸搜索API返回参数说明

有访问参数,在访问成功后,进行人脸识别,我们需要的便是识别之后的信息,因此读懂API的返回参数是项目中非常重要的技能。百度AI人脸识别项目中,需要根据返回参数进行对应的信息接收、处理和显示。人脸搜索API文档中,请参考返回说明章节。
(1)、返回参数介绍

  • face_token:人脸标志 ,String类型

  • user_list:返回用户信息 ,字典类型

    • group_id:所属的用户组(在那个班级) ,String类型
    • user_id:用户名称,String类型
    • user_info:注册用户时携带的user_info,String类型
    • score:用户的匹配得分,当分数大于80的时候,默认人脸识别成功,float类型

(2)返回参数示例
在这里插入图片描述
在这里插入图片描述
在经过以上第一大步骤的进行之后,便可以开始我们接下来的代码编写了,在我们的《百度AI人脸识别与检测》项目中,通过以上了解的到的相关知识,完成人脸识别模块的功能。请继续往下面看!


二、完成系统人脸识别功能模块

1、定义人脸识别数据接收和发送信号

在人脸识别完成之后,我们首先需要处理的便是人脸识别信息数据,将这些数据送到PyQT对于功能的控件上显示。但前面的代码我们了解到,在进行人脸检测是在子线程中,而数据的显示是在主线程中的窗口上面,因此,首先我们需要定义一个变量,用该变量存储人脸识别信息,并将子线程中得到的变量传递到主线程。而pyqt5中通过pyqtSignal信号接口实现了子线程与主线程之间的变量传递。
(1)、在detect.py文件中,定义transmit_data1信号,用于子线程与主线程中的人脸识别数据交互,信号类型为字符串型。

transmit_data1 = pyqtSignal(str)  # 定义信号,用于子线程与主线程中的人脸识别数据交互

(2)、代码添加位置如下:
在这里插入图片描述

2、编写人脸搜索访问方法

(1)通过人脸搜索API文档规则,在detect.py文件尾部编写访问方法,代码如下所示:

# 人脸识别搜索检测,只识别一个人
    def face_search(self):
        request_url = "https://aip.baidubce.com/rest/2.0/face/v3/search"
        params = {
            "image": self.imageData,
            "image_type": "BASE64",
            "group_id_list": "class1",
        }
        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_msg'] == 'SUCCESS':
                if data['result']['user_list'][0]['score'] > 90: #大于90分,意味人脸识别成功
                    del [data['result']['user_list'][0]['score']]
                    datetime = QDateTime.currentDateTime()#获取人脸打开时间
                    datetime = datetime.toString()#将获取到的时间转为字符串
                    data['result']['user_list'][0]['datetime'] = datetime#将获取到的时间添加到返回的数据中
                    list1 = [data['result']['user_list'][0]['user_id'],data['result']['user_list'][0]['group_id']]#去除名字和班级
                    self.transmit_data1.emit("学生签到成功\n学生信息如下:\n" + "姓名:" + list1[0] + "\n" + "班级:" + list1[1])#将信号发送给主线程
  • image:通过人脸检测传递过来的图像
  • image_type:图像格式为base64
  • group_id_list:上面我们创建的class1用户组

3、调用函数,进行人脸识别

(1)人脸识别的基础是在人脸检测的基础上进行的,在人脸检测到之后,方可进行人脸识别,因此,在detect.py文件中的人脸检测函数中进行人脸识别方法的调用。

self.face_search()

(2)、代码添加位置如下:
在这里插入图片描述
(3)detect.py文件中的代码便修改完成,修改后的代码如下所示:

import requests
from PyQt5.QtCore import QThread, pyqtSignal, QDateTime


class detect_thread(QThread):
    transmit_data = pyqtSignal(dict)#定义信号,用于子线程与主线程中的人脸检测数据交互
    transmit_data1 = pyqtSignal(str)  # 定义信号,用于子线程与主线程中的人脸识别数据交互
    def __init__(self,access_token):
        super(detect_thread,self).__init__()
        self.ok=True#循环控制变量
        self.condition = False#人脸检测控制变量,是否进行人脸检测
        self.access_token=access_token#主线程获取的access_token信息传递给子线程并设置为全局变量
    #run函数执行结束代表线程结束
    def run(self):
        while self.ok==True:
            if self.condition==True:
                self.detect_face(self.imageData)
                self.condition=False
    '''
        接收主线程传递过来的图像
    '''
    def get_imgdata(self,data):
        #当窗口调用这个槽函数,就把传递的数据存放在线程的变量中
        self.imageData=data#将接收到图像数据赋值给全局变量
        self.condition=True#主线程有图像传递过来,改变condition的状态,run函数中运行人脸检测函数
    '''
        人脸检测
    '''
    def detect_face(self,base64_image):
        request_url = "https://aip.baidubce.com/rest/2.0/face/v3/detect"
        # 请求参数是一个字典,在字典中存储了,要识别的内容
        params = {
            "image": base64_image,  # 图片信息字符串
            "image_type": "BASE64",  # 图片信息的格式
            "face_field": "gender,age,beauty,mask,emotion,expression,glasses,face_shape",  # 请求识别人脸的熟悉,各个熟悉在字符中用,用逗号隔开
            "max_face_num": 10#能够检测的最多人脸数
        }
        # 访问令牌
        access_token = self.access_token
        request_url = request_url + "?access_token=" + access_token
        # 设置请求的格式体
        headers = {'content-type': 'application/json'}
        # 发送post网络请求,请求百度AI进行人脸检测
        response = requests.post(request_url, data=params, headers=headers)
        if response:
            data = response.json()
            self.face_search()
            self.transmit_data.emit(dict(data))#如果返回结果正确,则将返回信息传递给主线程

    # 人脸识别搜索检测,只识别一个人
    def face_search(self):
        request_url = "https://aip.baidubce.com/rest/2.0/face/v3/search"
        params = {
            "image": self.imageData,
            "image_type": "BASE64",
            "group_id_list": "class1",
        }
        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_msg'] == 'SUCCESS':
                if data['result']['user_list'][0]['score'] > 90: #大于90分,意味人脸识别成功
                    del [data['result']['user_list'][0]['score']]
                    datetime = QDateTime.currentDateTime()#获取人脸打开时间
                    datetime = datetime.toString()#将获取到的时间转为字符串
                    data['result']['user_list'][0]['datetime'] = datetime#将获取到的时间添加到返回的数据中
                    list1 = [data['result']['user_list'][0]['user_id'],data['result']['user_list'][0]['group_id']]#去除名字和班级
                    self.transmit_data1.emit("学生签到成功\n学生信息如下:\n" + "姓名:" + list1[0] + "\n" + "班级:" + list1[1])#将信号发送给主线程

下面就需要在主线程中进行数据接收显示了!

4、主线程人脸识别数据接收显示

(1)、在function_window.py文件末尾添加显示信息方法

    def get_seach_data(self,data):
        self.plainTextEdit.setPlainText(data)

在这里插入图片描述
(2)、在function_window.py文件中绑定子线程中信号接收

self.detect.transmit_data1.connect(self.get_seach_data)

添加位置如下图:
在这里插入图片描述
到这里,人脸识别模块基本完成,function_window.py文件也修改完成。
(3)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
from cameraVideo import camera
from mainWindow import Ui_MainWindow
from detect import detect_thread
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.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)

5、人脸识别运行结果测试

(1)运行程序,打开签到
在这里插入图片描述
(2)开始签到
在这里插入图片描述
可以看到,签到的数据显示到对应的信息框中,签到成功!
(3)关闭签到
在这里插入图片描述


以上就是本次博客的全部内容,遇到问题的小伙伴记得留言评论,学长看到会为大家进行解答的,这个学长不太冷!

没有人永远青春,但永远有人正青春;只是,林君学长的青春暂告一段路而已!

陈一月的又一天编程岁月^ _ ^

评论 27
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈一月的编程岁月

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值