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

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

作者: 小张Python | 来源:发表于2020-03-10 20:38 被阅读0次

    前序

    这篇文章主要介绍利用 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

    最后,感谢阅读!

    相关文章

      网友评论

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

          本文链接:https://www.haomeiwen.com/subject/hwngdhtx.html