Edited at

PepperとAzure Face APIで顔認証。

More than 1 year has passed since last update.

既に製品としての活用事例があるPepper × MS AzureのFaceAPIを試してみた。

ドキュメントがしっかりしていて、実装しやすいので是非お試しを..:heart_eyes:


Azure FaceAPI ざっくりしたまとめ

FaceAPIには、顔認証に欠かせない主なAPIが5つあります。顔の検出を行うDetect、顔の認識を行うIdentify、Verify、Find Similar、Groupです。


Face Detection(顔の検出)


Detect

写真から人間の顔を検出するAPI。


  • 検出された顔にはFaceIdが割り振られる。FaceIdの期限は、Detectコール後24時間。

  • 一つの画像から最大64の顔を検出

  • 画像は、バイナリもしくはURLで指定

  • 検出した顔の示す四角形(left, top, width, height)を取得できる

  • オプションで、gender, age, head pose, facial hair, glasses等の要素を取得できる

詳しくは、こちら

https://dev.projectoxford.ai/docs/services/563879b61984550e40cbbe8d/operations/563879b61984550f30395236


Face Recognition(顔認識)

顔を認識するためのAPIとして、以下の4つが用意されている。


Identify(顔識別)

Detectにより割り振られたFaceIdと一致する顔を、指定するPersonGroup(後述、顔のセット)から検索し、候補者を返すAPI。


  • 候補の顔は、類似点を計算しPersonGroupの中から高い順に候補を返す。

  • PersonGroupが事前にトレーニングされている必要がある。

  • 1回のリクエストで10人以内の顔を特定することができる。

詳しくは、こちら。

https://dev.projectoxford.ai/docs/services/563879b61984550e40cbbe8d/operations/563879b61984550f30395239


Verify(顔検証)

2つの顔(2つのDetectされた顔、もしくは、1つのDetectされた顔とPersonオブジェクト)が同一人物のものかどうかの認証をするAPI。

詳しくは、こちら。

https://dev.projectoxford.ai/docs/services/563879b61984550e40cbbe8d/operations/563879b61984550f3039523a


Find Similar(類似の顔を検出)

顔のセット(FaceList)を与えて、その中から問い合わせた顔(Detectされた顔)と類似の顔を検索するAPI。


  • 検索に使う顔のセットには、FaceList(後述)、もしくは、DetectされたFaceIdの配列を指定することができる。


  • matchPersonmatchFaceの2つのモードがある。



    • matchPersonは、顔の閾値を利用してできるだけ同じ人の顔を検索する。(ない場合は空で返される)


    • matchFaceは、閾値は無視して、類似性は低くとも、とにかく類似の顔としてランクされたものを返す



詳しくは、こちら。

https://dev.projectoxford.ai/docs/services/563879b61984550e40cbbe8d/operations/563879b61984550f30395237


Group(顔のグループ化)

Detectにより検出された複数の顔を、見た目の類似性に基づいてグループ化するAPI。


  • グループは 、似ている顔のグループ、MessyGroup(似ている顔が見つからなかった顔のグループ)に分けられる。

  • 少なくとも2以上の顔をが必要となる。最大で1000の顔をグルーピングすることができる。

  • 同一人物の顔が異なるグループに分けられていることがあるので注意が必要になる。

詳しくは、こちら

https://dev.projectoxford.ai/docs/services/563879b61984550e40cbbe8d/operations/563879b61984550f30395238


顔認証するために事前に用意する顔のセット

上記5つのAPIを使用するには、顔のセットを事前に登録しておく必要がある。

顔のセットとして、PersonGroupとFaceListの2つが用意されている。

使用するAPIによって、PersonGroupとFaceListを使い分ける。


Person Group

Identifyで使用される顔のセット。


  • グループの中に、一人の顔を表すPersonオブジェクト(後述)を、最大で1000まで登録できる。

  • Identifyでは、Person Groupの中のPersonの顔から特定する。

  • Person Groupを操作するAPIとして、生成・削除などのAPIが用意されている。

  • PersonGroupに新しいPersonオブジェクトを生成したり、Personオブジェクトの情報を更新した場合、PersonGroupをトレーニングさせる必要がある。(トレーニングされるまで情報は更新されない。)

詳しくはこちら

https://dev.projectoxford.ai/docs/services/563879b61984550e40cbbe8d/operations/563879b61984550f30395244


Person

Person Groupに含まれる、一人の情報を表すのがPersonオブジェクトである。


  • Personオブジェクトには、248枚までの画像を追加することができる

  • 中に含まれる顔の情報は、persistedFaceIdとして保持される。(FaceIdのような期限はない)

  • URLもしくは、バイナリデータにより顔を追加できる。

Person GroupとPersonオブジェクトの関係のイメージは以下のような感じです。

Identifyでは、以下のようなPersonを含むPerson Groupのどれかを指定し、顔を認証します。

personGroup_person.png

詳しくはこちら

https://dev.projectoxford.ai/docs/services/563879b61984550e40cbbe8d/operations/563879b61984550f3039523b


Face List

Face Listは、Find Similarで使用される顔のセットです。


  • Face Listは、顔のグループで、中に最大1000まで持つことができる。

  • Face Listに追加された顔に期限はない。

  • Face Listを操作するAPIとして、追加・削除等のAPIが用意されている。

詳しくはこちら

https://dev.projectoxford.ai/docs/services/563879b61984550e40cbbe8d/operations/563879b61984550f30395250


Pythonで実装。

顔の登録と認証をPepperで試してみました。認証はIdentifyで行います。


顔の登録

Personオブジェクトに顔を登録します。

※先にPersonオブジェクトを追加するためのPerson Groupを生成しておきます。

[流れ]


  1. Pepperのタブレットで入力された名前(登録名となる)を受け取る。

  2. 入力された名前を登録名として、Personオブジェクトを生成する(Create a Person)

  3. 作ったPersonにPepperのカメラで撮った顔を追加する(Add a Person Face)

  4. Personオブジェクトへの顔の追加が成功したら、PersonGroupのトレーニングをする(Train Person Group)

Choregrapheはこんな感じになりました。

スクリーンショット 2016-11-30 11.47.26.png


Create a Person

タブレットから名前を受け取ったら、Create a Personで、特定のPerson Groupに新しいPersonオブジェクトを追加します。

Create a Person APIを使用するための関数

#-----------------------------------

# Create a Person POST Request
# param1: name--Personオブジェクト登録名
# param2: user_data--説明(Optional)
#-----------------------------------
def create(self, name, user_data=None):
import requests, json
url = "https://api.projectoxford.ai/face/v1.0/persongroups/"
url += str(self.memory.getData("AzureData/PersonGroupId"))
url += "/persons"

#Request Header
headers = {
'ocp-apim-subscription-key': self.memory.getData("AzureData/SubscriptionKey"),
'Content-Type': "application/json"
}

#Request Body
payload = {
'name': name,
'userData': user_data
}

try:
res = requests.post(url, data=json.dumps(payload), headers=headers)
if res.status_code == 200:
return res.json()
else:
error = res.json()
errorCode = error["error"]["code"].encode("utf8")
self.logger.info(errorCode)
errorMessage = error["error"]["message"].encode("utf8")
self.logger.info(errorMessage)
return None

except requests.exceptions.RequestException as e:
self.logger.info(e)
return None


Add a Person Face

続いて、生成されたPersonオブジェクトに顔を追加します。

Add a Person Face APIを使用するための関数

#--------------------------------------------------------------

# Add a Person Face POST Request
# param1: image--画像のバイナリデータ
# param2: person_id--Create a Personで生成されたPersonオブジェクトのID
# param3: user_data--(Optional)
# param4: target_face--(Optional)
#--------------------------------------------------------------
def add_face(self, image, person_id, user_data=None, target_face=None):
import requests

personGroupId = self.memory.getData("AzureData/PersonGroupId")
url = "https://api.projectoxford.ai/face/v1.0/persongroups/" + personGroupId + "/persons/" + person_id + "/persistedFaces"

#Request Header
headers = {
'ocp-apim-subscription-key': self.memory.getData("AzureData/SubscriptionKey"),
'Content-Type': "application/octet-stream",
'cache-control': "no-cache",
}

#Request Body
params = {
'userData': user_data,
'targetFace': target_face,
}

try:
res = requests.post(url, headers=headers, params=params, data=image)
if res.status_code == 200:
return res.json()
else:
error = res.json()
errorCode = error["error"]["code"].encode("utf8")
self.logger.info(errorCode)
errorMessage = error["error"]["message"].encode("utf8")
self.logger.info(errorMessage)

#self.onFailure(errorMessage)

except requests.exceptions.RequestException as e:
self.logger.info(e)
#self.onFailure(e)


Train Person Group

顔が登録できたら、最後にPerson Groupをトレーニングします。

Train a Person Group APIを使用するための関数

#----------------------------

# Train a Person Group POST
#----------------------------
def train(self):
import requests, json

#SubscriptionKey
subscriptionKey = self.memory.getData("AzureData/SubscriptionKey")
#Person Group ID
personGroupId = self.memory.getData("AzureData/PersonGroupId")

url = "https://api.projectoxford.ai/face/v1.0/persongroups/"
url += str(personGroupId)
url += "/train"

#Request Header
headers = {
'ocp-apim-subscription-key': str(subscriptionKey),
'Content-Type': "application/json"
}

#Request Body
payload = {
'personGroupId': person_group_id
}

try:
res = requests.post(url, data=json.dumps(payload), headers=headers)
if res.status_code == 202:
return res
else:
self.logger.info(res.status_code)
#self.onFailure()

except requests.exceptions.RequestException as e:
self.logger.info(e)
#self.onFailure(e)


顔の認証

Identifyで、指定したPersonGroupの中の顔と一致するものがあるか、検索する。

[流れ]

1. Pepperのカメラの画像に人間の顔があるか、検知する。(Detect)

2. Detectで検知したFaceIdを使用して、PersonGroupから顔の認証を行う。(Identify)

3. 候補者が見つかったら、見つかった人のPersonIDから、その人の情報を取得する。(Get a Person)

Choregrapheは、下のようにしてみた。

スクリーンショット 2016-11-30 13.17.18.png


Detect

Pepperでイメージをキャプチャし、顔が存在するか確認しに行く。返されるFaceIdを使用して次のIdentifyを行う。

Detect APIを使用するための関数

#-------------------------------

# Detect POST Request
# param1: image--画像のバイナリデータ
#-------------------------------
def detect(self, image):
import requests

url = "https://api.projectoxford.ai/face/v1.0/detect"

#Request Header
headers = {
'ocp-apim-subscription-key': self.memory.getData("AzureData/SubscriptionKey"),
'Content-Type': "application/octet-stream",
'cache-control': "no-cache",
}

#Request Parameter
params = {
'returnFaceId': True,
'returnFaceLandmarks': False,
'returnFaceAttributes': "age,gender"
}

try:
res = requests.post(url, headers=headers, params=params, data=image)

if res == []:
self.noFaceDetected()
else:
self.logger.info(res)
if res.status_code == 200:
data = res.json()
#self.logger.info(data)
if data == []: #配列が空の場合、顔が検出されていない
self.noFaceDetected(data)
else:
#FaceId
faceid = data[0]["faceId"].encode("utf8")
#Gender
gender = data[0]["faceAttributes"]["gender"].encode("utf8")
self.memory.insertData("AzureData/Gender", gender)
#Age
age = data[0]["faceAttributes"]["age"]
self.memory.insertData("AzureData/Age", age)

self.onSuccess(faceid)
else:
self.logger.info(res.status_code)
error = res.json()
self.logger.info(error["error"]["message"].encode("utf8"))
self.onFailure(res.status_code)

except requests.exceptions.RequestException as e:
self.logger.info(e)
self.onFailure(e)


Identify

Detectから返されるFaceIdで、指定のPersonGroupから一致する顔を検索する。

Identify APIを使用するための関数

#-------------------------------

# Identify POST Request
# param1: face_ids --Detectで返されるFace IDの配列
# param2: max_candidates_return --Optional
# param3: threshold --Optional
#-------------------------------
def identify(self, face_ids, max_candidates_return=1, threshold=None):
import requests, json
url = 'https://api.projectoxford.ai/face/v1.0/identify'

#Request Header
headers = {
'ocp-apim-subscription-key': self.memory.getData("AzureData/SubscriptionKey"),
'Content-Type': "application/json"
}

#Request Body
payload = {
'personGroupId': self.memory.getData("AzureData/PersonGroupId"),
'faceIds': face_ids,
'maxNumOfCandidatesReturned': max_candidates_return,
'confidenceThreshold': threshold,
}

return requests.post(url, data=json.dumps(payload), headers=headers).json()


Get a Person

Identifyで特定された候補者のPersonIdから、Get a Personで名前を取得する。

Get a Person APIを使用するための関数


PythonScript.py

#-------------------------------

# Get a Person GET Request
# param1: personId --取得したいPersonオブジェクトのID
#-------------------------------
def get_a_person(self, personId):
import requests
personGroupId = self.memory.getData("AzureData/PersonGroupId")
url = "https://api.projectoxford.ai/face/v1.0/persongroups/" + personGroupId + "/persons/" + personId

#Request Header
headers = {
'ocp-apim-subscription-key': self.memory.getData("AzureData/SubscriptionKey"),
'Content-Type': "application/json"
}

return requests.get(url, headers=headers)



実際に顔認証してみて。

認証は問題なくできました!

年齢や笑顔といった要素は、少し怪しいのですが、認証は素晴らしい...:clap::clap:

Personオブジェクトには、5枚ほど顔を登録しました。

多く写真を登録するば、より正確なデータが得られるのか・・・?

IMG_1455.JPG