LoginSignup
5
6

More than 5 years have passed since last update.

FlashAir+Face API+FlashAir IoT Hubで人物カウンターを作ってみた

Last updated at Posted at 2017-01-07

 昨年10月に東芝無線LAN内蔵SDカード「FlashAir」をIoTデバイスとして活用するためのプラットフォームとして「FlashAir IoT Hub」が発表されました。現在、プレビュー公開が行われています。今回は、これにFlashAirからデータを送信して、グラフ表示することを試してみます。
 送信するデータは、デジタルカメラで撮影した写真画像ファイルをLuaスクリプトでFace APIを呼び出して、写った人物の男女別人数、年齢層別人数をカウントしたデータを送信することにします。

 ただ、今回、Cognitive ServicesのFace APIをFlashAirのLuaスクリプトから呼び出そうとしたのですが、どうしてもHTTP 415エラーとなり呼び出せませんでした。そのため、Computer Vision APIのvisualFeaturesに「Faces」を指定して、Face APIと同等の結果を得ることにしました。
 REST APIの仕様は、こちらのドキュメントComputer Vision API - v1.0を参照してください。

全体概要

FlashAirFaceAPI.png

FlashAir IoT Hubの準備

 こちらのFlashAir IoT Hubチュートリアルを参考に、準備してください。今回は、ご利用の流れのFlashAir登録まで済んでいれば大丈夫です。

FlashAirのファイル配置

 以下のファイルを配置しておきます。

・iothub.lua
 取得した「スクリプト」ファイルのひとつ、FlashAir IoT Hub SDKファイルです。
・credentials.json
 FlashAir IoT Hubのアクセストークン取得で取得したJSONファイルです。

今回利用するコマンド

 FlashAir IoT Hub SDK(iothub.lua)のなかのデータ送信機能addMeasurementを利用します。

iothub.addMeasurement(arg1, arg2, arg3, arg4, arg5)

使い方は簡単で、addMeasurementの引数に最大5個まで送信するデータを指定するだけです。

サブスクリプションキーの取得

 次に、Microsoft Cognitive Services - Computer Vision APIを利用するためのサブスクリプションキーを入手します。現時点では、月間5,000リクエストまで、または1分間に20リクエストまでは無料で利用できます。
 Microsoft Cognitive Services サブスクリプションに、自分のMicrosoftアカウント(もし、お持ちでなければ無料で作成できます)でログインします。すると、以下のようなページで各種APIのサブスクリプションキーを入手することができます。今回は、「Computer Vision API」のチェックをつけて、Subscribeボタンを押します。

subscriptions取得画面1.png

 つぎの画面で、以下のようにサブスクリプションキーが生成されます。Key 1のCopyという文字列をクリックすると、キー文字列がクリップボードにコピーされますので、どこかに保存しておいてください。後ほど使います。

subscriptions取得画面2.png

CONFIGファイルの設定

 FlashAirのSD_WLANフォルダ内のCONFIGファイルに、以下のLuaスクリプト起動オプションを付加します。

LUA_RUN_SCRIPT=/faceapi_sample.lua

 ※SD_WLANフォルダとCONFIGファイルは不可視属性ファイルなので注意してください。

Luaスクリプトファイル

 FlashAirのルートフォルダに以下のコードを記述したテキストファイル(faceapi_sample.lua)をコピーします。
 このスクリプトでは、最新の画像ファイルをDCIMフォルダ配下に探しに行きファイル名を取得、このファイルをComputer Vision APIに投げて、Facesの結果を得ます。得たJSONファイルのなかから必要なデータを取り出して、FlashAir IoT Hubに送信します。その後、1分待機して、同じ処理を繰り返します。
 処理を繰り返す中で、画像ファイルが更新されていない場合は、Face APIの呼び出しはスキップしますが、FlashAir IoT Hubには前回を同じデータを送信するようにしています。

faceapi_sample.lua
cjson = require "cjson"
iothub = require("iothub")
latest_fpath = ""
faces_num_00 = 0
faces_num_20 = 0
faces_num_60 = 0
faces_num_male = 0
faces_num_female = 0

function funcfacecount()
    last_fname = ""
    last_fpath = ""
    last_modif = 0

    last_moddir = 0
    last_dirname = "/DCIM"

    fpath = "/DCIM"
    for dirname in lfs.dir(fpath) do
      dirpath = fpath .. "/" .. dirname
      mod_dir = lfs.attributes( dirpath, "mode" )
      if mod_dir == "directory" then
        dir_modifficate = lfs.attributes( dirpath, "modification" )
        if dir_modifficate > last_moddir then
          last_moddir = dir_modifficate
          last_dirname = dirpath
        end
      end
    end

    for filename in lfs.dir(last_dirname) do
      if(string.sub(filename, 1, 1) ~= ".") then
        filepath = last_dirname .. "/" .. filename
        mod = lfs.attributes( filepath, "modification" )
        if mod > last_modif then
          last_modif = mod
          last_fname = filename
          last_fpath = filepath
        end
      end
    end

    if(latest_fpath == last_fpath) then
      return
    end
    latest_fpath = last_fpath

    boundary = "1234567890"
    contenttype = "multipart/form-data; boundary=" .. boundary
    mes = "--" ..  boundary .. "\r\n"
      .."Content-Disposition: form-data; name=\"file\"; filename=\""..last_fname.."\"\r\n"
      .."Content-Type: image/jpg\r\n\r\n"
      .."<!--WLANSDFILE-->\r\n"
      .."--" .. boundary .. "--\r\n"

    blen = lfs.attributes(last_fpath,"size") + string.len(mes) - 17
    b, c, h = fa.request{url = "https://api.projectoxford.ai/vision/v1.0/analyze?visualFeatures=Faces",
      method = "POST",
      headers = {["Content-Length"] = tostring(blen),
      ["Content-Type"] = contenttype,
      ["Ocp-Apim-Subscription-Key"] = "ここにサブスクリプションキーを記述する",
      file = last_fpath,
      body = mes
    }

    if(c == 200) then
      res = cjson.decode(b)

      for idx=1,#res.faces do
        local agenum = tonumber(res.faces[idx].age)
          if(agenum < 20) then
          faces_num_00 = faces_num_00 + 1
        elseif(agenum >= 20 and agenum < 60) then
          faces_num_20 = faces_num_20 + 1
        elseif(agenum >= 60) then
          faces_num_60 = faces_num_60 + 1
        end

        if( res.faces[idx].gender == "Female" ) then
          faces_num_female = faces_num_female + 1
        else
          faces_num_male = faces_num_male + 1
        end
      end
    end
end

while(1) do
  funcfacecount()
  iothub.addMeasurement({faces_num_00, faces_num_20, faces_num_60, faces_num_male, faces_num_female})
  sleep(60000)
  collectgarbage("collect")
end

動作確認

 今回は、著作権フリー写真・イラスト素材集のサンプル画像で動作確認をしてみました。まずはFlashAirに適当な画像ファイルをコピーしてみます。1分ごとに画像ファイルをComputer Vision APIで分析して、その画像に写っている人物の認識結果がうまくグラフに表示されました。
 FlashAir IoT Hubでは5つのデータまでしか送信できないため、今回は、(1)20歳以下の人数、(2)20〜60歳の人数、(3)60歳以上の人数、(4)男性の人数、(5)女性の人数の5つのデータを送信しています。

faceapi_sample1.png

まとめ

 FlashAirからCognitive ServicesのComputer Vision APIを呼び出して、写真に写っている人物の男女別人数と年齢層別人数をカウントすることができるようになりました。
 デジタルカメラでインターバル撮影を行えば、定点観測による人物カウンターが実現できますね。

参考資料

 FlashAir IoT Hubチュートリアル
 Microsoft Cognitive Services - Computer Vision API
 Microsoft Cognitive Services - Computer Vision API - Document

5
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
6