Pyqt5 + 百度 API 打造一个图像人脸识别、分割的程序

2020-03-10  本文已影响0人  小张Python

前序

这篇文章主要介绍利用 pyqt5 和 百度人脸识别 api 搭建一个具有人脸识别、头像裁剪等多个功能集一体的小工具,我们先看一下程序的最终效果

end_imag11.gif

程序的基本使用步骤:

1,加载本地图片并在界面上实现预览;

2,点击 convert 后台调用百度 api 实现人脸识别并进行区域分割,同时返回关于人物颜值、性别、脸型等信息;

3,如果需要保存裁剪之后的图像,点击 Save as 保存到本地对应位置;

Snipaste_2020-03-07_16-44-44.jpg

整个程序的实现分为三个部分:

1,获取百度 api 实现人脸识别接口并进行调用;

2,利用Qt designer 进行界面设计,编写代码实现一些功能函数;

3,把1功能和2的界面进行信号槽链接;

2,程序开发详细过程

2.1,获取百度人脸识别 API 接口并进行调用;

对于人脸识别 API 接口 ,这里只是以百度为例,百度人脸识别 API 的地址 :https://ai.baidu.com/tech/face;利用这个接口,可以很方便地返回我们需要的信息

百度 API 构造基本流程:创建应用 -> 获取 API Keys 和 Secret Keys -> 得到 token -> 利用 token 拼API ;

首先需要完成登录(账号百度云即可),登录之后会进入下面这个界面,左侧栏列出了 人脸识别 专区提供的一些服务,有技术文档(关于怎么获取接口,以及怎样使用接口)、监控报表(调用接口的基本情况)....

Snipaste_2020-03-05_01-03-42.jpg

如果第一次使用需创建一个应用,用于获取 API key 和 Secret key

Snipaste_2020-03-05_01-04-29.jpg

根据官网文档,拿到 API key 和 Secret Key 之后,拼接成一个链接,利用 requests 进行访问得到 token ,(注: token 的有效时间为30天,30天之后如果继续使用的话,需要更换)

import requests 

# client_id 为官网获取的AK, client_secret 为官网获取的SK
host = 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=【官网获取的AK】&client_secret=【官网获取的SK】'
response = requests.get(host)
if response:
    print(response.json()['access_token'])

token 拿到之后,与下面链接拼接在一起就得到了API 接口:

https://aip.baidubce.com/rest/2.0/face/v1/merge?access_token=[获取得到的Token]

API 的使用方法如下:

import requests

'''
人脸检测与属性分析
'''
request_url = "https://aip.baidubce.com/rest/2.0/face/v3/detect"

params = "{\"image\":\"027d8308a2ec665acb1bdf63e513bcb9\",\"image_type\":\"FACE_TOKEN\",\"face_field\":\"faceshape,facetype\"}"
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())

其中 headers 不用改变,access_token 就是前面获取得到的 token ;重点是 params 参数,里面需要写入三个参数: image,image_type,image_filed:

image 当image_type = BASE64,填入图片base64编码(指的是本地文件);
当image_type = URL,填入图片链接
当image_type = FACE_TOKEN,填入图片 FACE_TOKEN;
image_type BASE64:图片的base64值,base64编码后的图片数据,编码后的图片大小不超过2M;
URL:图片的 URL地址( 可能由于网络等原因导致下载图片时间过长);
FACE_TOKEN: 人脸图片的唯一标识,调用人脸检测接口时,会为每个人脸图片赋予一个唯一的FACE_TOKEN,同一张图片多次检测得到的FACE_TOKEN是同一个。
image_filed 指的是你想要的信息,例如:age,beauty,expression,face_shape,gender,glasses,landmark,landmark150,race,quality,eye_status,emotion,face_type

image 的 BASE64 编码值指的时本地文件读取, 可以利用 base64.b64enconde 函数进行获取,params 也可以写成键值对字典形式:

params = {
                'image': str(base64.b64encode(open(file_name, 'rb').read()), 'utf-8'),#file_name指的时图片的本地路径;
                'image_type': 'BASE64',
                'face_field': 'age,beauty,expression,face_shape,location,gender'
            }

官方文档对于 image_filed 介绍的很详细,下面我贴上其中一部分,更详细的可以参考:https://cloud.baidu.com/doc/FACE/s/yk37c1u4t ;

Snipaste_2020-03-05_10-29-20.jpg

为了后面的获取人脸裁剪位置,这里在 image_filed 中加入了 location 参数,返回的结果中会有 location json 格式数据 ,里面有人脸 left、width、top、height 等坐标参数;得到这 4 个参数之后,用 **PIL 的 image.crop ** 函数得到人脸裁剪图像

关于图像人脸的全部信息会以 json 格式返回,requests 使用接口时需要注意的是 post 方式;到这里 人脸识别API 获取及使用方法已经介绍完毕了。

2.1,利用qt designer 进行界面设计;

这里自己偷了个懒,不想写代码,直接用 qt designer 工具设计了一个简单界面(下面是初期的界面,后面用代码改了一部分):

Snipaste_2020-03-05_10-58-33.jpg

界面中用两个 Label 来放置原图和裁剪之后的图片,背景设为不同颜色,左下角用三个 pushbutton 来作为打开、保存、裁剪按钮(上图中的界面在后续用代码做了一些改动)。

界面的右下角就是用于预览 人脸识别后的信息:年龄、性别、颜值、脸型等。

Qt designer 设计好的界面以 ui 文件保存,用 PyGUI 工具把 .ui 转化为 .py

2.3,界面信号—槽链接

这一步就是把 2.1 获取得到的信息 在 2.2 中的设计的界面进行链接,用专业一点术语就是 信号槽链接,在此之前需要构造槽函数

首先,实现open 读取图片、预览功能函数,按钮信号槽链接;

    self.pushButton.clicked.connect(self.open_file)#signal-slot connect
    
    def open_file(self):
        file_name = QFileDialog.getOpenFileName(self,"Open file..","/",'all files:(*.png);;(*.jpg)')
        if file_name[0]:#File exits
            #clear the contend of label;
           self.label.clear()
           self.label_2.clear()
           self.file_name = file_name[0]
           print("file name: {}".format(str(self.file_name)))
           img = Image.open(self.file_name)
           pixmap = ImageQt.toqpixmap(img)
           self.label.setPixmap(pixmap)
           self.label.setScaledContents(True)
           self.pushButton_2.setEnabled(True)

        else:
            QMessageBox.warning(self,"waring","文件为空无法转换")

其次,实现 **Convert **按钮链接、图片裁剪、信息显示功能:

 self.pushButton_2.clicked.connect(self.get_date)#signal-slot connect
 
 
 def get_token(self):#get token
        get_token_url = 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id={}&client_secret={}'.format(
            self.api, self.keys)
        try:
            res = requests.get(get_token_url).json()['access_token']
            return str(res)
        except:
            return 0

    def get_date(self):
        if self.file_name:
            params = {
                'image': str(base64.b64encode(open(self.file_name, 'rb').read()), 'utf-8'),
                'image_type': 'BASE64',
                'face_field': 'age,beauty,expression,face_shape,location,gender'
            }
            headers = {'content-type': 'application/json'}
            # 构造百度人脸检测请求url,获取token;,
            token = self.get_token()
            res_url = "https://aip.baidubce.com/rest/2.0/face/v3/detect?access_token={}".format(str(token))
            res = requests.post(res_url, data=params, headers=headers)
            try:
                total_list = res.json()['result']['face_list']
                loacation = total_list[0]['location']
                left = int(loacation['left']) - 10
                upper = int(loacation['top']) - 10
                right = int(loacation['left']) + int(loacation['width']) + 10
                bottom = int(loacation['top'] + int(loacation['height'])) + 10
                img = Image.open(self.file_name).crop((left, upper, right, bottom))
                print(res.json())
                self.crop_pixmap = ImageQt.toqpixmap(img)
                self.label_2.setPixmap(self.crop_pixmap)
                self.label_2.setScaledContents(True)

                age = total_list[0]['age']
                print(age)
                self.lineEdit.setText(str(age))

                self.lineEdit.setAlignment(Qt.AlignCenter)
                gender = total_list[0]['gender']['type']
                print(gender)
                self.lineEdit_2.setText(str(gender))
                self.lineEdit_2.setAlignment(Qt.AlignCenter)
                beauty = total_list[0]['beauty']
                self.lineEdit_3.setText(str(beauty))
                self.lineEdit_3.setAlignment(Qt.AlignCenter)
                face_shape = total_list[0]['face_shape']['type']
                self.lineEdit_4.setText(str(face_shape))
                self.lineEdit_4.setAlignment(Qt.AlignCenter)


                # Save pushbutton 保存一致;
                self.pushButton_3.setEnabled(True)

            except:
                QMessageBox.warning(self,'error','Face recognise failed!')
        else:
            QMessageBox.information(self,'info','The file path of pic is not exist!')

裁剪图像保存,save 按钮信号槽连接:

    self.pushButton_3.clicked.connect(self.save_file)# signal-slot connect
    
    
    def save_file(self):
        self.pushButton_3.setEnabled(True)
        name = QFileDialog.getSaveFileName(self,'Save file','/','png:(*.png);;jpg:(*.jpg)')
        if name[0]:
            img = ImageQt.fromqpixmap(self.crop_pixmap)
            img.save(str(name[0]))
            QMessageBox.information(self,'info','{} saved successfully'.format(str(name[0])))
        else:
            QMessageBox.warning(self,'error','{} saved failed'.format(str(name[0])))

3,关于 API接口的一点吐槽

以上就是关于 人脸识别小程序 制作的完整过程,感兴趣的同学也可以试一下,完整源码获取方式:在公众号:Z先生点记 后台回复关键字 人脸识别 即可。

在程序制作过程中,对百度 人脸识别API 做次性能测试, 在 meizi图 网站 抓了400来张图片,分别调用API进行识别、裁剪,并把返回的年龄、性别等信息保存到 excel 表格中;

原图就不放了,下面是裁剪后图片,裁剪的效果还是不错的,

Snipaste_2020-03-05_11-55-41.jpg

但是识别年龄方面存在一点问题:返回的基本都是在21-23整个区间,也不知道是爬取图片中的妹子都这么年轻,还是公开的 API 在年龄识别方面具有局限性。

Snipaste_2020-03-05_12-00-33.jpg

最后,感谢阅读!

上一篇下一篇

猜你喜欢

热点阅读