Check! Python から Cognitive Services の REST API を使ってみる ～ おばかIoT選手権の裏側

こんにちは、オークファンの @dz_ こと大平かづみです。

Prologue - はじめに
====
[おばかIoT選手権](https://obakapp.doorkeeper.jp/events/44982 "おばかIoTアプリの応募（おばかIoT選手権 2016 Summer選手募集） - おばかアプリ選手権 | Doorkeeper") に応募したくて、なんとかネタをひねり出しました！(笑) （投稿動画は [こちら](https://www.facebook.com/dzeyelid/videos/1116777285012260/) ）


その名も、「めがねチェッカー β」

*日々の生活に欠かせないめがね。忘れてはならないめがね。*

*しかし、仕事や勉強に忙しいあなたは、ついめがねを忘れて家を出ることも… そんなことがないように、このメガネチェッカー β があなたの代わりに日々確認・記録を行い、より快適な生活をご提案していく。*

*めがねチェッカー β はいつもあなたのそばに* 👓

本題
====
さて！まじめな話を書くと、以下の構成で画像に目的のものが写っているかどうかを日々プロットしていくシステム（？）を作りました。

システム構成
------------
- [Raspberry Pi Zero](https://www.raspberrypi.org/products/pi-zero/ "Raspberry Pi Zero - Raspberry Pi")
- [BUFFALO Webカメラ BSWHD06MWH](http://amzn.to/29uUqo3 "iBUFFALO マイク内蔵120万画素Webカメラ HD720p対応モデル ホワイト BSWHD06MWH") 割引で991円でした！
- Python
- [Cognitive Services](https://www.microsoft.com/cognitive-services "Microsoft Cognitive Services")
    - [Computer Vision API](https://www.microsoft.com/cognitive-services/en-us/computer-vision-api "Microsoft Cognitive Services - Computer Vision API")
- [Azure](https://azure.com/ "Microsoft Azure: Cloud Computing Platform & Services")
    - [Table Storage](https://azure.microsoft.com/ja-jp/services/storage/tables/ "Table Storage | Microsoft Azure")
    - [PowerBI](https://powerbi.microsoft.com/ "Power BI | 対話型のデータ視覚化 BI ツール")

実装のポイント
==============
今回のポイントをまとめておきます。サンプルコードを後述してますので、併せてご参考いただければ幸いです。

Webカメラの静止画撮影
--------------------
Raspberry Pi で UVC対応の Web カメラで静止画を撮影する方法については、こちらを参考にしました。

- [Using a standard USB webcam](https://www.raspberrypi.org/documentation/usage/webcams/ "Using a standard USB webcam - Raspberry Pi Documentation")

```bash
# fswebcam のインストール
$ sudo apt-get install fswebcam

# 静止画を撮影する（下部に撮影時刻が印字される）
fswebcam capture.jpg

# 静止画を撮影する（撮影時刻を印字しない）
fswebcam --no-banner capture.jpg
```

Cognitive Services の利用
-------------------------
Cognitive Services および Computer vision API については、こちらに軽くまとめました。

- [Check! 画像に何が写っているのかを知る ～ Cognitive Services を使ってみよう](http://qiita.com/dz_/items/eedc03c73f978318fc92 "Check! 画像に何が写っているのかを知る ～ Cognitive Services を使ってみよう")

Power BI で Table Storage のデータを利用する方法
-----------------------------------------------
IoT で Power BI を利用する方法はいくつかあります。

今回は時間がなかったので、とりいそぎ Azure Table Storage に格納し、あとから Power BI に取り込める方法を採用しました。

Power BI に Table Storage のデータを取り込むには、 [Power BI Desktop](https://powerbi.microsoft.com/en-us/desktop/ "Power BI Desktop | Microsoft Power BI") を利用します。

![20160717_powerbi_azure-table-storage_001.png](https://qiita-image-store.s3.amazonaws.com/0/3812/5fdf59dc-b7b7-34b6-d3e3-88d6969d8b53.png)

また、別の方法で、 Event Hubs → Stream Analytics → Power BI という流れを利用すると、ほぼリアルタイムなデータを Power BI に入力することができます。下記のハンズオン資料の 54ページ目からその手順をご紹介しています。ご参考になれば幸いです。

- [ ITAP第11弾「初めてのフィジカルコンピューティング」](https://doc.co/5oMTg3 "ITAP第11弾「初めてのフィジカルコンピューティング」")

Python ライブラリ のインストール
-------------------------------
### Azure SDK

Azure にデータを保存するために、 [Azure SDK for Python](https://github.com/Azure/azure-sdk-for-python "GitHub - Azure/azure-sdk-for-python: Microsoft Azure SDK for Python") をインストールします。現行は 1.x ですが 2.x がリリースされているので指定してインストールしました。

```bash
# azure sdk for python の 2.x をインストールする
$ sudo pip install --pre azure
```

#### Azure Storage SDK について
上記でご紹介した Azure SDK for Python のうち Storage 周りは、内包している  [Azure Storage SDK for Python](http://azure-storage.readthedocs.io/en/latest/index.html "Azure Storage SDK for Python. &mdash; Azure Storage SDK for Python 0.20.3 documentation") を利用する形になっています。

今回利用した Table Storage の利用方法に関しては、下記のドキュメントをご参照くださいませ。

- [Table Storage — Azure Storage SDK for Python 0.20.3 documentation](http://azure-storage.readthedocs.io/en/latest/table.html)


### Requests
Python でHTTPリクエストを送信するには、 [Requests](http://requests.readthedocs.io/ "Requests: HTTP for Humans — Requests 2.10.0 documentation") というライブラリがおすすめのようです。実際使ってみたところ、とってもわかりやすくシンプルなコードが書けました。

私の Rasbian の環境ではもうインストールされていたので、バージョンアップのみ行いました。

```bash
# requests をインストールする
$ sudo pip install requests

# または、バージョンアップする
$ sudo pip install --upgrade requests
```

サンプルコード
=============
ご参考までにソースコードを公開します。突貫で書いたのであまりきれいでなく恐縮ですが、最低限の動作はします。ご参考になれば幸いです。

ここで行っている処理は以下です。

- UVC対応Webカメラの静止画撮影
- Requests ライブラリを用いた Computer Vision API の利用
- Azure SDK (Azure Table Storage) の利用 

ソースコード
------------
`sample.py` と、後述の `config.ini` は同ディレクトリに配置します。

```py:sample.py
import os
import json
import time
import subprocess   # to execute command on sub process
import requests     # for HTTP/HTTPS Request
import ConfigParser # to parse config.ini 
from azure.storage.table import TableService, Entity # to use azure table storage

# Get file path
current_path = os.path.dirname(__file__)
file_path = current_path + '/images/capture.jpg'

# Remove file
os.remove(file_path)

# Take a picture
cmd = 'fswebcam --no-banner ' + file_path
subprocess.call(cmd.strip().split(' '))

# Load config.ini
config = ConfigParser.SafeConfigParser()
config.read(current_path + '/config.ini')

# Send a request to analyze the picture
url = 'https://api.projectoxford.ai/vision/v1.0/analyze'
params = {'visualFeatures':'Description'}
headers = {
    'Ocp-Apim-Subscription-Key': config.get('settings', 'subscription_key')}
files = {'file': open(file_path, 'rb')}

r = requests.post(url, params=params, headers=headers, files=files)

# Check whether the picture include glasses
tags = json.loads(r.text)['description']['tags']
result = 'glasses' in tags

print tags

if result == True:
    print 'Your Megane is nice!'
else:
    print 'You forget something important...'

# Save data to Azure Table Storage
account = config.get('azure', 'storage_account')
key = config.get('azure', 'storage_key')
table_name = config.get('azure', 'table_storage_name')
partition_key = config.get('azure', 'table_storage_partition_key')
current_time = time.strftime('%Y-%m-%dT%H:%M:%SZ')

table_service = TableService(account_name=account, account_key=key)

tables = table_service.list_tables()

if not (table_name in tables):
    table_service.create_table(table_name)

table_service.insert_entity(
    table_name,
    {
        'PartitionKey': partition_key,
        'RowKey': current_time,
        'Megane': result,
        'tags': json.dumps(tags),
        'Date': current_time,
    }
)
```

```ini:config.ini
[settings]
subscription_key = XXXX

[azure]
storage_account = XXXX
storage_key = XXXX
table_storage_name = XXXX
table_storage_partition_key = XXXX
```

なお、 `ConfigParser` で設定値を読み込む `config.ini` の書き方で、 `=` の右側の文字列はクオートで囲わないようにします。クオートで囲うと、クオートまで値として取得されてしまいます。

Epilogue - おわりに
====
このシステム（？）は、カメラを宅配で受け取った1 0時ごろから 24時までの約1日で、一人ハッカソン状態で作りました。特に、大きくつまづくことなく作り上げることができ、様々なソリューションの恩恵を感じながら便利な時代になったなーと感心しておりました！