機械学習で用いる顔画像データセットの一作り方（１：WebAPIサービスを用いて候補画像取得）


DNN等の機械学習を用いて画像認識・分類を行う場合、学習実行時に大量の訓練用画像が必要となるため、
web等で公開されているデータセット（画像集合）を用いるケースが多くあるかとあります。
しかし顔画像分類・認識の場合には肖像権等の問題もあるためにフリーで公開されてるデータセットが少なく、
結果として学習画像を集めるのに苦慮されてる方も多いと思います。
そこで顔画像データセットを自作する一方法をここで紹介しておきます。

#今回用いた開発環境
+ MacOS X El Capitan 10.11.4 
+ Python 3.5
+ OpenCV 3.1


#候補画像の取得

まず目的となる顔が写っている可能性がある画像（以下、候補画像と呼ぶ）を収集します。
考えられる収集方法としては以下の手法があります。

+ 一般公開されているWebAPIサービスを用いて収集
+ 動画をフレーム解析して収集
+ webページをスクレイピングして収集

そのうち今回は **WebAPIサービスを用いた候補画像の収集方法** について書きたいと思います。


#一般公開されているWebAPIを用いた候補画像の収集
web上やSNSにて公開されている画像情報をレスポンスとして返すWebAPIサービスは多数存在しますが、
ここでは[Microsoft Cognitive Services](https://www.microsoft.com/cognitive-services)で無料提供されている **Bing Image Search API** を用います。

今回のBing Image Search APIを用いた収集法では、

1. 検索条件をクエリに設定し、それに見合った画像のURLをAPIにて取得
2. 1で得た画像URLから、OpenCVにて画像コピーを新たに作成

という2つの手順を踏みます。
そのため上記にもありますが、importするライブラリとしてOpenCVが必要となります。

### Bing Image Search API を使う手順
Microsoft Cognitive Servicesの登録、及びBing Image Search API利用登録手順は
別記事にてアップしておりますのでそちらをご覧ください。
[Microsoft Cognitive Servicesの登録方法](http://qiita.com/ligerbolt/items/516b59d64e6059586ec6)

なおAPIを利用する際には、API登録完了時に取得できるサブスクリプションキーが必要となります。

###APIから検索結果である画像情報を取得するコード例
基本的には一般的なWebAPI同様、HTTPメソッド（今回はgetリクエスト）をAPIエンドポイントへ投げることで、
クエリの検索結果である画像URLを格納したレスポンス情報（json形式）を受け取れます。
それを実現したコード例が以下のようになります。


```python
# _*_ coding: utf-8 _*_

import requests
import urllib.request
import os.path
import cv2
import numpy as np

# APIのEndPointとSubscription Key
REQUEST_BASE_URL = 'https://bingapis.azure-api.net/api/v5/images/search'
SUBSCRIPTION_KEY = '********************'


def api_request(query, count=10):

    # headerとparameter設定
    headers = { 'Ocp-Apim-Subscription-Key': SUBSCRIPTION_KEY, }
    params = {
        'q': str(query),
        'count': int(count),
        'mkt': 'ja-JP',
        'offset': '0',
    }

    # APIスロー
    response = requests.get(REQUEST_BASE_URL, headers=headers, params=params)
    res_headers = response.headers
    status_code = response.status_code
    results = None

	# ステータスコードやheader内容に応じて呼出元へ返す内容設定
    if status_code == 200:
        if 'content-length' in res_headers and int(res_headers['content-length']) == 0:
            results = None
        elif 'content-type' in res_headers and isinstance(res_headers['content-type'], str):
            if 'application/json' in res_headers['content-type'].lower():
                results = response.json()['value']['contentUrl'] if response.content else None
            else
                results = None
    else:
        # ステータスコードが200以外なら強制終了
        print("Error! - status code : {0}".format(response.status_code))
        print("Message : {0}".format(response.json()['error']['message']))
        exit()

	# 検索結果である画像URLを返す　
    return results
```
　
APIのリクエスト時・レスポンス時の各詳細な仕様は[公式APIリファレンス](https://msdn.microsoft.com/en-us/library/dn760791(v=bsynd.50).aspx)を参照してください。
ここではリクエスト時に最低限必要と思われる仕様だけを記しておきます。
###リクエストヘッダ情報
| 情報項目 | 内容 |
|:---------:|:------------:|
| Ocp-Apim-Subscription-Key   |サブスクリプションキー文字列|
###リクエストパラメータ
| パラメータ項目 | データ型|内容 |
|:---------:|:------------:|:------------:|
| q       |String|検索クエリとなる文字列|
|count|UnsignedShort|レスポンスで返す検索結果の画像数|
|mkt|String|リクエスト要求を発送している地域名（Market Codeで指定）|
　
なお今回はAPIのレスポンス情報より検索結果である画像URLのみを取得していますが、
他にもBing Image Search APIでは以下の情報が取得可能です。

- 画像の画素サイズ
- 画像のファイルサイズ
- 画像が掲載されているページのURL
- 画像タイトル
- サムネイル画像のURL・サイズ
　

###画像URLから候補画像を作成するコード例
上記メソッドより検索結果の画像URL集合を取得したら、
そのURLからOpenCVを用いることで候補画像を新たに作成します。

```python
def make_image(image_url):
	# URLの画像情報をロード
	resp = urllib.request.urlopen(image_url)

	# OpenCVで読み込めるよう画像のメモリバッファ再構築
	image = np.asarray(bytearray(resp.read()), dtype=np.uint8)
	
	# メモリバッファより画像読み込み
	image = cv2.imdecode(image, cv2.IMREAD_COLOR)

	# 新たな画像として書き出す
	cv2.imwrite("hoge.jpg", image)
```
　
メモリバッファ再構築の際にはデータ型をuint8型に設定してやります。
これは一般的に画像を構成する画素値が区間 [0,255] 内の整数値をとるからです。
またimdecodeメソッドによる画像読み込みの際に`cv2.IMREAD_COLOR`を指定することで、
カラー画像として読み込まれます。
　
以上簡単ではありますが、Bing Image Search APIを用いた候補画像収集例を説明しました。
[次回](http://qiita.com/ligerbolt/items/fdfe836e71a2c0247a79)は動画をOpenCVでフレーム解析して、候補画像を収集する方法を書いていきます。