[微笑偵測器] 微軟辨識服務搭配Arduino

本文要介紹微軟辨識服務的Face API,可以偵測照片中的臉孔以及相關參數,包含年齡、性別、情緒、眼鏡、鬍子以及五官座標等。

作者/攝影  曾吉弘
時間   3小時
成本
難度  * * * * *
材料表
  • 個人電腦
  • Arduino Uno 或其他可執行 StandFirmata 之 Arduino相容板
  • LED x 3
  • 線材
  • 麵包板

本範例修改自微軟辨識服務Face API教學而來,您也可以在該頁面找到其他程式語言的教學。

微軟辨識服務

根據官方網站說法:Microsoft 辨識服務具備多種程式語言的API,可以透過自然的溝通方式看、聽、說,以及理解和解讀各種媒體素材,包然文字、語音、照片、影片與搜尋建議等等。分成五大類,每項又各自分成不同細項,本範例將使用辨識下的臉部API:

  1. 辨識
  2. 語音
  3. 語言
  4. 知識
  5. 搜尋

 

註冊Face API

註冊一個新的帳號,需要手機號碼認證與信用卡認證…

  • 這些步驟完成之後選擇您要的API,即可取得金鑰(subscription key),每一個API各自會有自己的流量與次數限制,請注意。
  • 下圖是 Face API 的兩組金鑰,使用任何一組都可以

 

在其頁面就可以看到效果,有一些範例圖片或者您可以自行上傳照片,右側就是偵測結果,格式是JSON,各主要程式語言對於JSON都有現成的函式庫來爬取。

範例程式

本範例是修改自 Face API python 範例程式而來,使用 python 2.7。本範例會使用一張網路圖片(#37)送到 Face API之後取得其辨識結果。

程式#33可指定我們所要偵測的臉孔參數,包含以下:

  • age:年齡
  • gender:性別
  • headPose:頭部姿態,回傳XYZ軸傾斜狀態
  • smile:微笑(0~1之間小數,數字愈高代表微笑愈明顯)
  • facialHair:臉部髮型,例如山羊鬍、八字鬍、鬢角
  • glasses:偵測有無戴眼鏡
  • emotion:情緒,包含生氣、滿足、害怕、驚訝與悲傷等等
  • hair:髮型,包含禿頭、髮色等等
  • makeup:偵測是否化妝
  • occlusion:偵測是否閉合,例如眼睛、嘴巴
  • accessories:配件
  • blur:偵測圖片是否模糊,以及模糊程度參數
  • exposure:偵測圖片曝光程度與曝光程參數
  • noise:偵測圖片中雜訊與雜訊程度參數

 

在此用到的圖片是這位可愛的女生,您可以換成其他的圖片來測試

import httplib, urllib, base64, json

###############################################
#### Update or verify the following values. ###
###############################################

# Replace the subscription_key string value with your valid subscription key.
subscription_key = 'XXXX' #填入Face API金鑰,任一組都可以

# Replace or verify the region.
#
# You must use the same region in your REST API call as you used to obtain your subscription keys.
# For example, if you obtained your subscription keys from the westus region, replace
# "westcentralus" in the URI below with "westus".
#
# NOTE: Free trial subscription keys are generated in the westcentralus region, so if you are using
# a free trial subscription key, you should not need to change this region.
uri_base = 'westcentralus.api.cognitive.microsoft.com'

# Request headers.
headers = {
'Content-Type': 'application/json',
'Ocp-Apim-Subscription-Key': subscription_key,
}

# Request parameters.
params = urllib.urlencode({
'returnFaceId': 'true',
'returnFaceLandmarks': 'false',
'returnFaceAttributes': 'age,gender,headPose,smile,facialHair,glasses,emotion,hair,makeup,occlusion,accessories,blur,exposure,noise',
})

# The URL of a JPEG image to analyze.
body = "{'url':'https://how-old.net/Images/faces2/main0011.jpg'}"

try:
# Execute the REST API call and get the response.
conn = httplib.HTTPSConnection('westcentralus.api.cognitive.microsoft.com')
conn.request("POST", "/face/v1.0/detect?%s" % params, body, headers)
response = conn.getresponse()
data = response.read()

# 'data' contains the JSON data. The following formats the JSON data for display.
parsed = json.loads(data)
print ("Response:")
print (json.dumps(parsed, sort_keys=True, indent=2))
print parsed[0]["faceAttributes"]["smile"] #第一張臉的 smile 強度
conn.close()

except Exception as e:
print("[Errno {0}] {1}".format(e.errno, e.strerror))

 

根據Face API,一張照片最多可以辨識到64張臉,但這樣真的太多了… 在基礎練習最好使用單一臉孔來測試。熟悉之後可以加入更多臉孔甚至連續偵測

參考:[微軟認知服務] 串流影像之臉孔與年齡辨識

執行結果如下,本範例就是把所有JSON結果顯示出來(#50),但為了後續微笑偵測,我們在#51獨立把smile的強度抓出來了,如下圖的 1.0

print parsed[0][“faceAttributes”][“smile”] #取得第一張臉的 smile 強度

上圖可愛小妹妹的完整偵測JSON結果如下,您可以慢慢檢視:

[
{
"faceAttributes": {
"accessories": [],
"age": 21.6,
"blur": {
"blurLevel": "low",
"value": 0.1
},
"emotion": {
"anger": 0.0,
"contempt": 0.0,
"disgust": 0.0,
"fear": 0.0,
"happiness": 1.0,
"neutral": 0.0,
"sadness": 0.0,
"surprise": 0.0
},
"exposure": {
"exposureLevel": "goodExposure",
"value": 0.73
},
"facialHair": {
"beard": 0.0,
"moustache": 0.0,
"sideburns": 0.0
},
"gender": "female",
"glasses": "NoGlasses",
"hair": {
"bald": 0.03,
"hairColor": [
{
"color": "brown",
"confidence": 1.0
},
{
"color": "black",
"confidence": 0.77
},
{
"color": "other",
"confidence": 0.46
},
{
"color": "red",
"confidence": 0.2
},
{
"color": "blond",
"confidence": 0.06
},
{
"color": "gray",
"confidence": 0.02
}
],
"invisible": false
},
"headPose": {
"pitch": 0.0,
"roll": -11.5,
"yaw": -5.6
},
"makeup": {
"eyeMakeup": true,
"lipMakeup": true
},
"noise": {
"noiseLevel": "low",
"value": 0.08
},
"occlusion": {
"eyeOccluded": false,
"foreheadOccluded": false,
"mouthOccluded": false
},
"smile": 1.0
},
"faceId": "d87447bd-a4b3-4c87-b92d-736871e8e6d9",
"faceRectangle": {
"height": 166,
"left": 175,
"top": 197,
"width": 166
}
}
]
1.0 #獨立抓出來的 smile 強度

您可以使用 jsoneditoronline.org 來檢視 json 結構,會比直接看原始資料來的清楚明暸。

 

pyfirmata

取得臉孔資訊之後就有很多東西可以玩了,例如本範例的微笑偵測器。或是找找看畫面中誰有戴眼鏡。如果是連續偵測的話,還能做到讓攝影鏡頭跟著你的臉孔中心移動(PTZ平台),總之太多應用啦!

pyfirmata 是python透過序列埠來與Arduino溝通的模組,Arduino端只要上傳(請先確認)StandardFirmata 這個程式就可以了,安裝完成請關閉Arduino IDE,後續用不到了~

 

請在 terminal 中使用以下指令來安裝 pyfirmata

pip install pyfirmata

 

Arduino端設定

python透過序列埠控制Arduino LED

 

本範例就是 python 版的 LED 閃爍,您可以比較一下兩者的差異,您只要確定COM port 邊與您電腦上的一致即可。如果是 MAC/ Linux,應該是 /dev/ttyUSB0 這樣的東西。如果是 Raspberry Pi 則應該是 /dev/ttyACM0

#!/usr/bin/python

import pyfirmata
import time
pin = 13
port = 'COM5'
board = pyfirmata.Arduino(port) #對指定序列埠開啟通訊
while True:
board.digital[pin].write(1) #設定指定腳位高電位
time.sleep(1) #等候1秒
print "ON : %s" % time.ctime() #顯示相關訊息與時間
board.digital[pin].write(0)
time.sleep(1)
print "OFF : %s" % time.ctime()

執行畫面如下圖,除了Arduino D13 會亮暗之外,在console上也有對應的訊息

Python結合Arduino微笑偵測應用

來看一下綜合運用吧!本範例會根據畫面中臉孔的微笑程度來決定LED亮起的數目。

import httplib, urllib, base64, json, pyfirmata
from time import sleep
port = 'COM5'

# Replace the subscription_key string value with your valid subscription key.
subscription_key = 'XXX' #填入Face API金鑰,任一組都可以

# NOTE: Free trial subscription keys are generated in the westcentralus region, so if you are using
# a free trial subscription key, you should not need to change this region.
uri_base = 'westcentralus.api.cognitive.microsoft.com'

# Request headers.
headers = {
'Content-Type': 'application/json',
'Ocp-Apim-Subscription-Key': subscription_key,
}

# Request parameters.
params = urllib.urlencode({
'returnFaceId': 'true',
'returnFaceLandmarks': 'false',
'returnFaceAttributes': 'age,gender,smile,emotion,occlusion,accessories,exposure,noise',
#'returnFaceAttributes': 'age,gender,headPose,smile,facialHair,glasses,emotion,hair,makeup,occlusion,accessories,blur,exposure,noise',
})

# The URL of a JPEG image to analyze.
body = "{'url':'https://how-old.net/Images/faces2/main002.jpg'}"

#connect Arduino
board = pyfirmata.Arduino(port) #對指定序列埠開啟連線
sleep(3) #等候3秒來開啟序列連線

try:
# Execute the REST API call and get the response.
conn = httplib.HTTPSConnection('westcentralus.api.cognitive.microsoft.com')
conn.request("POST", "/face/v1.0/detect?%s" % params, body, headers)
response = conn.getresponse()
data = response.read()
# 'data' contains the JSON data. The following formats the JSON data for display.
parsed = json.loads(data)
print ("Response:")
print (json.dumps(parsed, sort_keys=True, indent=2)) #顯示所有資料
a = parsed[0]["faceAttributes"]["smile"] #顯示微笑程度
conn.close()

except Exception as e:
print("[Errno {0}] {1}".format(e.errno, e.strerror))

print "smile value is"
print a #顯示微笑程度
if a > 0.75: #以下分成三個區間來控制LED,您可以自行修改
board.digital[9].write(1)
board.digital[10].write(1)
board.digital[11].write(1)
print 111
elif a < 0.25:
board.digital[9].write(1)
board.digital[10].write(0)
board.digital[11].write(0)
print 100
else:
board.digital[9].write(1)
board.digital[10].write(1)
board.digital[11].write(0)
print 110

 

執行!

執行時,Moto GP 傳奇車手 Valentino Rossi~ https://moto7.tw/imgs/valentino-rossi-2015.jpg,也可以看到100代表只會亮起一個LED代表 Rossi 現在只有微笑或是沒表情。您可以切分更多條件或是修改Arduino端的呈現效果,一起來微笑吧!

延伸

 

請改用以下語法來將本機端圖檔上傳到FACE API來做辨識,請注意這個圖檔需要與 .py 放在同一個資料夾中,不然就需要指定絕對路徑。為了程式精簡,我們把 Arduino 端拿掉,您可以根據上續範例修改即可。

 

f = open(‘7688.jpg’, ‘rb’)

jpgdata = f.read()

f.close()

 

完整程式如下:

import httplib, urllib, base64
import json

f = open('a006.jpg', 'rb')
jpgdata = f.read()
f.close()

# Request header
headers = {
# Request headers
'Content-Type': 'application/octet-stream',
'Ocp-Apim-Subscription-Key': 'd3d138ceb1f4470286dcaba79f7d2de9',
}

params = urllib.urlencode({
# Request parameters
'returnFaceId': 'true',
'returnFaceLandmarks': 'false',
'returnFaceAttributes': 'age,gender,smile,emotion,glasses',
}) #只需要上述五個參數


body = {
}

try:
conn = httplib.HTTPSConnection('api.projectoxford.ai')
#conn.request("POST", "/face/v1.0/detect?%s" % params, json.dumps(body), headers)
conn.request("POST", "/face/v1.0/detect?%s" % params, jpgdata, headers)
response = conn.getresponse()
data = json.loads(response.read())
print(json.dumps(data, indent=2)) #顯示所有資料
print data[0]["faceAttributes"]["smile"] #顯示微笑程度
conn.close()
except Exception as e:
print("[Errno {0}] {1}".format(e.errno, e.strerror))

 

相關文章:

 

 

 

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *