前序
这篇文章主要介绍利用 pyqt5 和 百度人脸识别 api 搭建一个具有人脸识别、头像裁剪等多个功能集一体的小工具,我们先看一下程序的最终效果
程序的基本使用步骤:
1,加载本地图片并在界面上实现预览;
2,点击 convert 后台调用百度 api 实现人脸识别并进行区域分割,同时返回关于人物颜值、性别、脸型等信息;
3,如果需要保存裁剪之后的图像,点击 Save as 保存到本地对应位置;
整个程序的实现分为三个部分:
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 ;
首先需要完成登录(账号百度云即可),登录之后会进入下面这个界面,左侧栏列出了 人脸识别 专区提供的一些服务,有技术文档(关于怎么获取接口,以及怎样使用接口)、监控报表(调用接口的基本情况)....
如果第一次使用需创建一个应用,用于获取 API key 和 Secret key
根据官网文档,拿到 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 ;
为了后面的获取人脸裁剪位置,这里在 image_filed 中加入了 location 参数,返回的结果中会有 location json 格式数据 ,里面有人脸 left、width、top、height 等坐标参数;得到这 4 个参数之后,用 **PIL 的 image.crop ** 函数得到人脸裁剪图像
关于图像人脸的全部信息会以 json 格式返回,requests 使用接口时需要注意的是 post 方式;到这里 人脸识别API 获取及使用方法已经介绍完毕了。
2.1,利用qt designer 进行界面设计;
这里自己偷了个懒,不想写代码,直接用 qt designer 工具设计了一个简单界面(下面是初期的界面,后面用代码改了一部分):
界面中用两个 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接口的一点吐槽
以上就是关于 人脸识别小程序 制作的完整过程,感兴趣的同学也可以试一下,完整源码获取方式:在公众号:小张Python 后台回复关键字 人脸识别 即可。
在程序制作过程中,对百度 人脸识别API 做次性能测试, 在 meizi图 网站 抓了400来张图片,分别调用API进行识别、裁剪,并把返回的年龄、性别等信息保存到 excel 表格中;
原图就不放了,下面是裁剪后图片,裁剪的效果还是不错的,
但是识别年龄方面存在一点问题:返回的基本都是在21-23整个区间,也不知道是爬取图片中的妹子都这么年轻,还是公开的 API 在年龄识别方面具有局限性。
最后,感谢阅读!