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

前序

这篇文章主要介绍利用 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接口的一点吐槽

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

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

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

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

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

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

最后,感谢阅读!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容

  • 认证授权: 在开始调用任何API之前需要先进行认证授权,具体的说明请参考: http://ai.baidu.com...
    才能我浪费阅读 1,115评论 0 0
  • 首先认证授权: 在开始调用任何API之前需要先进行认证授权,具体的说明请参考: http://ai.baidu.c...
    才能我浪费阅读 1,887评论 0 0
  • 早安【日精进第139天/3650用生命影响生命!如何过一天就如何过一生! 没有反思的 人生不值得过!!(湖北省恩施...
    好心情_d8eb阅读 99评论 0 0
  • 我觉得我得了很严重的病。 严重到什么地步呢?不想混入人群之中,想彰显自己特立独行的同时又想显得超凡脱俗,不与我认为...
    逝小西阅读 243评论 0 0
  • 1:有一天,楼下的超市搞活动,人比较多。所有人都排着队,耐心地等着。等到快要到我了,一个大妈突然插队到我前面。 “...
    何十九阅读 721评论 1 7