2016.01.08

Intel EdisonとAzure APIを活用して年齢性別判定装置を作成


IoTのビッグウェーブに乗り遅れないためにIntel Edisonを購入し勉強している次世代システム研究室のJ.Nです。

Intel EdisonとはCPU、WiFi、Bluetoothが入ったSDカードサイズのコンピューターモジュールです。

Linuxがデフォルトで入っているので、SSH接続しすぐにプログラミングができます。

Intel Edison で始めるIoT開発

今回はこの小さいコンピューターの活用事例として、Microsoft Azure APIと組み合わせた年齢性別判定装置を作ってみたいと思います。

構成図は以下です

azure1

実際にはタッチセンサーを用いてタッチセンサーにタッチしたら写真を撮り、画像をAzureMLに送信するようにします。

用意するパーツ

購入した装置は以下になります。

組み立て

 

phot11o
  1. Arduinoボードに、Intel Edisonのチップを接続します
  2. Arduinoボートに、ベースシールドを接続します
  3. USBカメラを接続します
  4. ベースシールドの適当なポートにLCDを接続します
  5. ベースシールドの適当なポートにタッチセンサーを接続します
注意点としてはベースシールドのスイッチをV5にしないとLCDで正しく文字が表示されません。
USBカメラは接続するだけでLinuxが自動的にドライバを読み込み使えるようになります。(dmesgで確認できます)

画像ファイルをAzure(Project Oxford)に送信し結果を受け取る

Project Oxfordとはマイクロソフトのクラウド機械学習サービスの一部で、画像解析に特化したクラウドサービスになります。
REST API形式でAPIを実行することができ、クライアントプログラムは画像を送信しOxfordが瞬時に解析した結果を受け取ることができます。

プログラミング言語としてはIntel EdisonのLinuxでは標準でPython2、Node.jsが利用できます。
RubyやJavaも追加できるのですが、ライブラリが欠損していたりうまく動かなかったりするので最初はPython2 or Node.jsでIntel Edisonを操作するのを推奨します。まずはIntel Edisonのpython2で画像をAzureMLに送信するプログラムを作成します。

./config/application.json
{
  "Azure" : {
    "subscription_key": ""
  }
}
photo.py
########### Python 2.7 #############
import httplib, urllib, base64
import sys
 
import json
f = open('./config/application.json', 'r')
config = json.load(f)
f.close()
 
headers = {
    # Request headers
    'Content-Type': 'application/octet-stream',
    'Ocp-Apim-Subscription-Key': config['Azure']['subscription_key'],
}
 
params = urllib.urlencode({
    # Request parameters
    'visualFeatures': 'All',
})
 
try:
    argv = sys.argv
    data = open(argv[1], "r+b").read()
    conn = httplib.HTTPSConnection('api.projectoxford.ai')
    conn.request("POST", "/vision/v1/analyses?visualFeatures=All", data, headers)
    response = conn.getresponse()
    data = response.read()
    print(data)
    conn.close()
except Exception as e:
    print("[Errno {0}] {1}".format(e.errno, e.strerror))
コマンドラインの第一引数の画像ファイルをAzureMLに送信し、返却されたJSON(年齢性別が入ったデータ)を標準出力にprintします。
次に、タッチセンサーにタッチがあったらWEBカメラを起動し撮影しその画像をAzureMLに送信し結果をLCDに表示するプログラムを作成します。

touch_and_shot.js
// 外部プログラミングを起動させるため必要
var exec = require('child_process').exec;
var photo_counter = 0;
 
// mraaはIntel Edisonから機器を操作するためのライブラリ
var mraa = require("mraa");
 
// LCD Classを定義
var LCD  = require("jsupm_i2clcd");
 
// LCDを初期化。0x3EはLCD_ADDRESS,0x62はRGB_ADDRESS。
// !注意! 第一引数のポートは実際にベースシールドに刺したポート番号にすること
var myLCD = new LCD.Jhd1313m1(6, 0x3E, 0x62);
 
var gender = "";
var age = 0;
var wait = 0;
 
// !注意! 第一引数のポートは実際にベースシールドに刺したポート番号にすること
var touch = new mraa.Gpio(2);
touch.dir(mraa.DIR_IN);
 
function readTouch() {
    // タッチセンサーにタッチがあったらここでログが出力される
    //console.log("Gpio is " + touch.read());
    
    if (touch.read() == 1) {
        shot();
    }
}
setInterval(readTouch, 1000);
 
// 写真を撮影する
function shot() {
      if (wait == 1) {return;}
      wait = 1;
      var time_string =  new Date().getTime();
      var filename = time_string + ".jpg";
      exec("fswebcam -r 1600x1200 /media/sdcard/photo/" + filename, function(err, stdout, stderr){
          exec("python /home/root/photo.py /media/sdcard/photo/" + filename, function(err, stdout2, stderr){
              console.log(filename);
              console.log(stdout2);
              // photo.pyの結果をパースする
              ret = JSON.parse(stdout2);
                console.log(ret);
                myLCD.setColor(0, 200, 0);
              // 配置(row,clumn)を指定 第一引数の「0」は1行目を示す
                myLCD.setCursor(0,0);
              if (ret['faces'].length > 0) {
                   myLCD.write("age:" + ret['faces'][0]['age'] + " " + ret['faces'][0]['gender'])
                   if (ret['faces'][0]['gender'] == 'Male') {
                       // 男性だったらLCDを青
                       myLCD.setColor(0, 0, 255);
                   } else {
                       // 女性だったらLCDを赤
                       myLCD.setColor(255, 0, 0);
                   }
                  
              } else {
                  // LCDに書き出し(写真に人が写ってなかったら「No Faceを表示」)
                  myLCD.write("No Face! -_-");
              }
              wait = 0;
         });  
      });
  photo_counter++; 
  // LCDの2行目 第一引数の「1」が2行目を示す、第二引数は文字のポジション
  myLCD.setCursor(1,0);
  myLCD.write("pc:" + photo_counter);
    
}


プログラムのポイントを解説すると
  • Intel Edisonから機器を制御するにはmraaライブラリを使用する
  • LinuxからWEBカメラを制御するコマンドはいくつかあるが今回はfswebcamを使用(Intel Edisonにインストールが必要)
  • Azureに画像を送信中にタッチセンサーが動いて再度写真を送信するのを防ぐためwait変数で、画像処理中は再度撮影しないように制御(あまり連続でAzureAPIを叩くと一時的にAPIからBANされます)
node touch_and_shot.jsでプログラムを起動しカメラの前に立ちタッチセンサーを触ると1秒程度でLCDが点灯します。

 

CRkjWhiUcAAom4d.jpg_large-1

 

私自身を撮影すると、age:23 Male(男性)・・と表示されました。(本当の年齢は秘密です)

※「Sec~」の部分はテストの時の表示なので無視してください。

今回学んだ事

  • Intel EdisonからのWEBカメラ制御
  • Intel Edisonからのタッチセンサー制御
  • Intel EdisonからのLCDディスプレイ制御
  • pythonでのAzureML Project Oxford API操作

まとめ

今回はIntel EdisonとクラウドAPIを使用して年齢性別判定プログラムと装置を開発しました。
このアプリケーションを発展させてデジタルサイネージでその人の年齢・性別に合った商品を紹介するといったものを作ると面白いと思います。

似たようなアプリケーションはスマートフォンのカメラを使っても作成できますが、Intel Edisonの強みの1つとしてLinuxがそのまま入っている自由な環境でのプログラミングが可能と言う点がスマートフォンのアプリ開発と比べて優っていると感じました。
今日の記事をきっかけにIntel Edisonを使って様々なプログラミング言語でのIoTアプリケーション開発を楽しんでいただけると幸いです。

最後に

次世代システム研究室では、アプリケーション開発や設計を行うアーキテクトを募集しています。アプリケーション開発者の方、次世代システム研究室にご興味を持って頂ける方がいらっしゃいましたら、ぜひ 募集職種一覧 からご応募をお願いします。