Microsoft Emotion APIをRaspberryPiで使用してみる【requests版】

Microsoft Emotion APIをRaspberryPiで使用してみる

前回のエントリではMicrosoftEmotionAPIをテストサイトで実験することろまでやってみました。

uepon.hatenadiary.com

今回は多分に漏れずこれをRaspberryPiのpython(2系)から制御したいと思います。 テストの対象にした画像は以下になります。前回のlenaさんで検索したら違う玲奈さんが出てしまった。

https://pbs.twimg.com/profile_images/486393178153439232/iqm-9kRQ_400x400.png

pythonソースコード

公式サイト内のドキュメントをみれば主要なプログラミング言語のサンプルは載っています。 ただし、JSONをつかってURLを送信するパターンが限定であることと、urllibを使用ものだけとなっています。

Microsoft Cognitive Services

サンプルソースとしてはこれで申し分ないのですが(特にpythonは2系と3系の両方が書かれているのですばらしいサンプルページだと思います)、 個人的にはpythonのRequestsモジュール(http://docs.python-requests.org/en/master/)を使用することが多いのでこちらの使用を考えました。

JSON(Web上にアップされた画像)を使用するパターン

APIのテストページそのままの処理になります。

import requests
import json
import types

url = 'https://api.projectoxford.ai/emotion/v1.0/recognize'
payload = {'url':'https://pbs.twimg.com/profile_images/486393178153439232/iqm-9kRQ_400x400.png'}
headers = {'Content-type': 'application/json', 'Ocp-Apim-Subscription-Key':'発行されたKey'}

r = requests.post(url, data=json.dumps(payload), headers=headers)
data = r.json()
dict = data[0]['scores']
max_key = max(dict, key=(lambda x: dict[x]))

print "key: %s,\t value:%f" %(max_key, dict[max_key])

処理としてはRequestsのPOSTメソッドを使ってAPIのURLへアクセスします。 その際のヘッダには

headers = {'Content-type': 'application/json', 'Ocp-Apim-Subscription-Key':'発行されたKey'}

のようにKeyValueスタイルの値を渡します。Ocp-Apim-Subscription-Keyには登録時に発行されたキーを入力してください。

参考f:id:ueponx:20161016233525j:plain

POSTするデータの内容は以下のような

payload = {'url':'https://pbs.twimg.com/profile_images/486393178153439232/iqm-9kRQ_400x400.png'}

keyValueスタイルで変数に格納します。実際にはpythonの辞書型のオブジェクトなのでアクセスする際にはJSONデータに変換する必要があります。

アクセスするURL、HTTPヘッダ、解析する画像のURLを含んだJSONデータの準備ができたので以下のようにアクセスを行います。

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

解析の結果はrとという変数に格納されますのでこれを解析することになります。

data = r.json()
dict = data[0]['scores']
max_key = max(dict, key=(lambda x: dict[x]))

結果からJSONデータを取り出し、その中のscoresから値が最大になるようなキーの値をmax_keyに格納する処理になります。maxをそのまま使うと、最大値のValueが取得されるのですが、このようにlambdaを使えばValueが最大値となるKeyを取り出すことができます。やっていることはそれほど難しくありません。

あとはprintで画面表示しています。

ローカルにある画像をOctet-Streamとして使用するパターン

JSON形式では画像がインターネット上にある必要があります。そのためにストレージの置場を作るのが難しい場合にはこちらを使うことになります。このパターンはなぜかサンプルに載ってなかったので作ってみました。

MicrosoftさんとしてはAzure上のストレージサービスにBLOB領域を作ってねって感じなのかもしれません。

以下のようなコードになります。

import requests
import json
import types

url = 'https://api.projectoxford.ai/emotion/v1.0/recognize'
headers = {'Content-type': 'application/octet-stream', 'Ocp-Apim-Subscription-Key':'発行されたKey'}
payload = open('解析したい画像ファイルのPATH', 'rb').read()

r = requests.post(url, data=payload, headers=headers)
data = r.json()
dict = data[0]['scores']
max_key = max(dict, key=(lambda x: dict[x]))

print "key: %s,\t value:%f" %(max_key, dict[max_key])

基本的な処理はほとんど変わりません。変更があるとすれば * HTTPヘッダのContent-typeがapplication/octet-streamに変更になる点 * ローカルにあるファイルをバイナリ形式で読み込む点 以上の2つになります。

HTTPヘッダは以下のようになります。

headers = {'Content-type': 'application/octet-stream', 'Ocp-Apim-Subscription-Key':'発行されたKey'}

Content-typeの値が変わっているのがわかるかと思います。

続いて、対象となる画像データをバイナリ形式で読み込みます。

payload = open('解析したい画像ファイルのPATH', 'rb').read()

後残りの処理は先ほどのJSONアクセスのパターンと全く同じになります。

まとめ

今回は同じ画像を使用してみましたが、結果はどちらの方式を使用しても同じ値が帰ってきました。ローカルファイルを使用する後者のほうががRaspberryPiでは使いやすいかもしれません。

本体のカメラで撮影して映っている人の表情を読み取ってGPIOの制御をするのも簡単に出来そうです。例えば帰宅時に奥さんの機嫌がいいとか悪いとかを教えてくれるようなガジェットはすぐに作れそうですねwそんな用途に使いたくないですけど。

/* -----codeの行番号----- */