PepperのAPIを使って年齢認識

Choregrapheの [ヘルプ] - [参照API] を開くとNAOqi Frameworkが提供するさまざまなAPIの情報を参照することができます。
この記事では、APIの使い方を、 **ALPeoplePerception API** と **ALFaceCharacteristics API** を例に説明していきます。

なお、 **ALPeoplePerception API, ALFaceCharacteristics APIともにバーチャルロボットでは動作確認手段はなく、Pepper実機が必要になります。** アルデバラン・アトリエ秋葉原などでPepper実機を使って実験などおこなってみていただければと思います。 (予約URL：http://pepper.doorkeeper.jp/events)

#この記事で紹介するAPI

##ALPeoplePerception API

**People Perception(人の認識)** APIは、[Pepperチュートリアル (6)：タッチセンサー、人の認識](http://qiita.com/Atelier-Akihabara/items/0a5826fb018a4d0e4268#1-4)でも見てきたとおり、Pepperの周辺の人を検知、識別する機能を提供するAPIです。

人がPepperのセンサーにより検出されると一時的な識別用のIDが設定され、その情報が `ALMemory` と呼ばれる領域に格納されます。
アプリケーションは、`ALMemory`を介して`ALPeoplePerception`によるイベントを取得して何か処理をおこなったり、`ALPeoplePerception`が`ALMemory`に保存した情報を利用することが可能です。

このAPIは以下のような、人の認識にかかわる情報を提供します。

* Pepperが認識している人の識別情報一覧
    * 新たな人の認識、人を見失ったといった変化イベント
* 認識している人ごとの属性情報
    * Pepperとの相対距離、位置などの情報
    * 視界に入っているか否か、顔を検出しているか否か
    * シャツの色

##ALFaceCharacteristics API

**FaceCharacteristics(顔の特徴)** APIは、`ALPeoplePerception`が認識した各人に関して、顔の情報を分析し、年齢や性別、笑っているかなどの追加情報を取得するAPIです。

`ALFaceCharacteristics`は、顔の特徴から推定された、以下のような情報を提供します。

* 年齢 ... 推定された年齢(0歳～75歳)
* 性別 ... 推定された性別(男性/女性)
* 笑顔度 ... 笑顔とみなせる度合い(0.0～1.0)

これらの各値には、確信の度合いを示す値として0～1の値があわせて提供されます。また、これ以外にも、以下のような値が提供されます。

* 表情 ... 無表情, 幸せ, 驚き, 怒り, 悲しみ の各表情のいずれにマッチしているかの評価値

#APIの利用方法

まず、これらのAPIを利用するにあたり、APIへのアクセス方法について整理します。
APIが提供する各種機能を利用するには、大きく分けて以下の2種類の方法があります。

1. `ALProxy`を介したモジュールのメソッド呼び出し
2. `ALMemory`を介したイベント、値の取得

ここでは、それぞれの方法について概要を説明していきます。

##ALProxyを介したモジュールのメソッド呼び出し

`ALPeoplePerception`, `ALFaceCharacteristics`といったAPIの多くは **モジュール** という形で提供されます。

モジュールはPythonのクラスによって提供されており、APIが提供するメソッドには `ALProxy` クラスを介してアクセスすることができます。
たとえば、 `ALFaceCharacteristics`が提供する`analyzeFaceCharacteristics`メソッドを呼び出すには以下のようなPythonスクリプトを記述します。

```py
faceChar = ALProxy("ALFaceCharacteristics")
faceChar.analyzeFaceCharacteristics(peopleId)
```

[Pythonボックス](http://qiita.com/Atelier-Akihabara/items/f6a05ca14be786f9a94c)のようにPepper内でPythonスクリプトを実行する場合は、 `ALProxy` にモジュール名を示す文字列を引数に指定することで、モジュールへのアクセス用の `ALProxy` インスタンスを得ることができます。これにより、アプリケーションはAPIが提供するメソッドを呼び出すことができます。

##ALMemoryを介したイベント、値の取得

[メモリイベント](http://qiita.com/Atelier-Akihabara/items/0a5826fb018a4d0e4268#3-3)の紹介の際にキーによるイベントの処理を紹介しましたが、Pepperの各種APIが収集した情報は `ALMemory` という機構にいったん集約されます。
アプリケーションは `ALMemory` に対して、以下のような操作をおこなうことができます。

* 値の設定、取得
* イベントの発行、監視

`ALMemory` の利用方法には以下のようなものがあります。

###フローダイアグラムによるイベント監視

フローダイアグラム左端に、メモリイベントによって反応する入力を作成することができます。

![flow-memory-event.png](https://qiita-image-store.s3.amazonaws.com/0/54394/78ee3943-bfc9-94e6-7bcd-bbd93d048ebd.png)

詳しい操作方法は、 [人の接近](http://qiita.com/Atelier-Akihabara/items/0a5826fb018a4d0e4268#3-5) などを参照してください。

###ボックスライブラリによる値取得、イベント監視

advancedボックスライブラリの Memory にあるボックスを利用することで、値の取得や設定、メモリイベントの監視などをボックスの組み合わせで実現することが可能です。

![memory-boxes.png](https://qiita-image-store.s3.amazonaws.com/0/54394/dd080a9a-0b4b-f272-0d2f-25ee9af18808.png)

この記事では **人の一覧の取得** を例に、ボックスの使い方を紹介します。

###Pythonスクリプトによる値取得、イベント監視

`ALMemory`も先に説明したモジュールとして実装されているので、以下のように`ALProxy`を介してアクセスすることができます。

```py
memory = ALProxy("ALMemory")
ageData = memory.getData("PeoplePerception/Person/%d/AgeProperties" % peopleId)
```

値の取得については、この記事では **年齢の推定** を例に紹介します。

#つかってみる

##サンプルプロジェクトの場所

ここで紹介するプロジェクトは、 https://github.com/Atelier-Akihabara/pepper-face-characteristics-example にて公開しています。

GitHub https://github.com/Atelier-Akihabara/pepper-face-characteristics-example からファイルを取得すれば、サンプルプロジェクトを利用することができます。取得方法にはいくつかありますが、[Download ZIP]リンクからアーカイブを取得するのが簡単な方法のひとつです。

得られたファイルには、 **visible-people-list** と **get-age** の2つのプロジェクトを示すフォルダがあります。このフォルダには拡張子 `.pml` ファイルがありますので、これをダブルクリックなどして開くことで、Choregrapheが起動し、プロジェクトを利用することができるようになります。

それぞれのサンプルプロジェクトについて、ポイントを説明していきます。

##ALPeoplePerception: 人の一覧の取得

まずは、 `PeoplePerception/VisiblePeopleList` イベントを利用して、**現在Pepperから見える位置にいる人の一覧を取得する** ことをおこなうことで、Pepperが人を認識した際の挙動について確認してみます。

サンプルプロジェクトは **visible-people-list** です。GitHubから取得したファイルのうち、 `visible-people-list` フォルダ内の `visible-people-list.pml` をダブルクリックするなどして開くことができます。
以下のような手順で作成しています。

1. フローダイアグラム左側の**メモリイベント追加[+]ボタンをクリック**し、フィルターに**PeoplePerceptionと入力[A]**し、**PeoplePerception/VisiblePeopleListをチェック[B]** します

    ![add-memory-event.png](https://qiita-image-store.s3.amazonaws.com/0/54394/1bcf1062-cf06-5ca8-6bc9-a3970d0e0937.png)

2. 以下のボックスをフローダイアグラムに配置します
    * standardボックスライブラリ
        * System > Log (2つ)
    * advancedボックスライブラリ
        * Memory > Get Data
3. 各ボックスの接続とパラメータを以下のように設定します

    ![visible-people-list.png](https://qiita-image-store.s3.amazonaws.com/0/54394/fc240adb-a1c3-6e4a-e732-ce5d8757700f.png)


このプロジェクトを実行し、[ログビューア](http://qiita.com/Atelier-Akihabara/items/7a898f5e4d878b1ad889#-%E5%8F%82%E8%80%83%E3%82%A8%E3%83%A9%E3%83%BC%E3%81%AE%E8%A1%A8%E7%A4%BA%E3%81%A8%E3%83%AD%E3%82%B0%E3%83%93%E3%83%A5%E3%83%BC%E3%82%A2)であらわれているメッセージを確認してみてください。人がPepperの周辺を動き回ると、以下のようなログが出力されるはずです。

```
[INFO ] behavior.box :onInput_message:27 _Behavior__lastUploadedChoregrapheBehaviorbehavior_1790002616__root__AgeDetection_5__Log_1: Get: []
[INFO ] behavior.box :onInput_message:27 _Behavior__lastUploadedChoregrapheBehaviorbehavior_1790002616__root__AgeDetection_5__Log_2: Raised: [179318]
```

`PeoplePerception/VisiblePeopleList` イベントにより、`179318` のような形で、Pepperから見える位置にいる人の識別子を列挙したリストが提供されていることがわかります。

次に、`ALFaceCharacteristics`を用いて、これらの識別子で示された人の顔の情報を取得してみましょう。

##ALFaceCharacteristics: 年齢の推定

次に、`ALFaceCharacteristics`の解析処理によって設定される値 `PeoplePerception/Person/<ID>/AgeProperties` の取得をおこなってみます。ここでは例として、**Pepperが見つけた人の年齢を推定して「あなたは？歳くらい」としゃべる**ことをやってみます。

なお、先ほどの例ではPepperが見つけた人すべてのIDを取得しましたが、ここでは、[Basic Awareness](http://qiita.com/Atelier-Akihabara/items/555989ab1d7d7e63e520#basic-awareness-breathing)の機能を利用することにします。standardボックスライブラリの Trackers > Basic Awarenssボックスを利用し人を追跡させ、その追跡している人のIDを `HumanTracked` 出力から得ることにします。

サンプルプロジェクトは **get-age** です。GitHubから取得したファイルのうち、 `get-age` フォルダ内の `get-age.pml` をダブルクリックするなどして開くことができます。
以下のような手順で作成しています。

1. 空のPythonボックスとして、Get Ageボックスを作成します
    今回は以下のような入出力構成にしています。作成方法は[Pythonボックスの考え方](http://qiita.com/Atelier-Akihabara/items/f6a05ca14be786f9a94c)などを参考にしてください。

    ![get-age-box.png](https://qiita-image-store.s3.amazonaws.com/0/54394/1f0e6076-bf08-42a2-1002-e86aca972672.png)

2. Get Ageボックスをダブルクリックしてスクリプトエディタを開き、以下のようなPythonスクリプトを記述します

    ```py
    class MyClass(GeneratedClass):
        def __init__(self):
            GeneratedClass.__init__(self)

        def onLoad(self):
            self.memory = ALProxy("ALMemory")
            self.faceChar = ALProxy("ALFaceCharacteristics")

        def onUnload(self):
            pass

        def onInput_onPeopleDetected(self, peopleId):
            if peopleId < 0:
                return
            r = self.faceChar.analyzeFaceCharacteristics(peopleId)
            if not r:
                self.onUnknown()
                return
            ageData = self.memory.getData("PeoplePerception/Person/%d/AgeProperties" % peopleId)
            self.logger.info("Age Properties: %d => %s" % (peopleId, ageData))
            if ageData and len(ageData) == 2:
                self.onAge(ageData[0])
            else:
                self.onUnknown()
    ```

    このコードでは、`onPeopleDetected`入力から与えられた人のIDに関して、 `ALFaceCharacteristics`の`analyzeFaceCharacteristics`メソッドを呼び出し、この呼び出しが成功した場合は、`ALMemory`から `PeoplePerception/Person/<ID>/AgeProperties` の値を取得し、この値のうち年齢を示す値を引数に`onAge`出力を呼び出しています。

3. 以下のボックスを配置します
    * standardボックスライブラリ
        * Trackers > Basic Awareness
        * Audio > Voice > Say
    * advancedボックスライブラリ
        * Audio > Voice > Say Text

4. Say TextボックスのTypeを [数] に変更し、[Say Textボックスのカスタマイズ](http://qiita.com/Atelier-Akihabara/items/8df3e81d286e2e15d9b6#%E8%A3%9C%E8%B6%B3say-text%E3%83%9C%E3%83%83%E3%82%AF%E3%82%B9%E3%81%AE%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%9E%E3%82%A4%E3%82%BA)を参考に、しゃべる内容を変更します

    ```py
    sentence += "あなたは%d歳くらい" % int(p)
    ```

5. 以下のように1.と3.で配置したボックスを接続します

    ![connect-get-age-box.png](https://qiita-image-store.s3.amazonaws.com/0/54394/e56d2c44-538a-c891-731e-dc89541493b4.png)

6. `onUnknown`出力につないだSayボックスの内容を「わからないです」などと変更します

このアプリケーションを実行すると、Basic Awarenessが起動し、Pepperが周囲の状況に反応して顔を向けるようになります。
人を見つけると、Get Ageボックスに人のIDが入力され、「あなたは？歳くらい」などとしゃべります。人を見つけても、顔が認識しにくい角度などの場合は認識処理が失敗し、「わからないです」としゃべります。

このようにして、**ALPeoplePerception API**, **ALFaceCharacteristics API**から得られた情報を利用し、PeoplePerceptionが認識している人に対して、年齢を推定するといったアプリケーションを実現することが可能です。ボックスライブラリに用意されていない機能でも、`ALProxy`, `ALMemory`を利用してAPIにアクセスすることで多くの機能を実現することができます。