38
44

More than 5 years have passed since last update.

PepperとAzure Face APIで顔認証。

Last updated at Posted at 2016-12-01

既に製品としての活用事例がある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

38
44
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
38
44