前序
這篇文章主要介紹利用 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接口的一點吐槽
以上就是關於 人臉識別小程序 製作的完整過程,感興趣的同學也可以試一下,完整源碼獲取方式:在公衆號(Z先生點記)後臺回覆關鍵字 人臉識別 即可。
在程序製作過程中,對百度 人臉識別API 做次性能測試, 在 meizi圖 網站 抓了400來張圖片,分別調用API進行識別、裁剪,並把返回的年齡、性別等信息保存到 excel 表格中;
原圖就不放了,下面是裁剪後圖片,裁剪的效果還是不錯的,
但是識別年齡方面存在一點問題:返回的基本都是在21-23整個區間,也不知道是爬取圖片中的妹子都這麼年輕,還是公開的 API 在年齡識別方面具有侷限性。
最後,感謝閱讀!