前編は、スマホの加速度センサーを使ってジェスチャーデータを作成するためのプログラムを作ります
こんにちは cedro です。
最近、スマホのセンサーを使って何かディープラーニングができないかと考え、色々情報収集をしていました。
そんな中、先週末(2/2) DELTA という勉強会に出席したところ、主催者の神谷さんから NNabla によるジェスチャー認識プログラムのプレゼンがありました。
この内容が大変素晴らしく、特に、実際作った10個のデータを10,570個にデータ拡張するとか、可変長データを固定長データに自在に変換するとか、マウスでジェスチャーしている最中に連続して推論実行するとか、とてもエキサイティングなものでした。(このプレゼンは、ブラッシュアップして、2/27のソニーのNeural Network Console大勉強会 #2 で発表されるそうなので、詳しい話はできませんが)
この件が大きな刺激となり、自分もジェスチャー認識プログラムを作ってみたくなりました。
神谷さんのプレゼンの様な高度なことはできませんが、シンプルな識別だけなら出来ると思います。但し、せっかくやるなら、ジェスチャーに使うデバイスは、マウスではなくてスマホにしてみようかと。
ということで、今回は前編と後編の2部構成で進めます。
前編は、スマホに内蔵されている加速度センサーを使ってジェスチャーデータを作成するためのプログラムを作ります。
スマホのセンサーの値を読み取るプログラム
スマホのセンサーの値を読み取るプログラムをどうやって作ろうかと思ってまず浮かんだのは、Android なら javaで android studio を使ってのプログラム開発 、iPhoneなら swiftで Xcodeを使ってのプログラム開発でした。
両者を比較すると、iPhoneの場合は、iOS Developer Program に登録する必要があり、これには年間100$掛かるため却下、Android の一択になりました。
そのため、Andoid プログラム開発に関する情報を色々物色したのですが、ほとんどの情報はAndroidの中で自己完結するプログラムばかりで(まあ当たり前と言えば当たり前ですが)思うようなプログラムは見つかりません。
そうこうしている内に、HTML5/Javascriptでの加速度センサー・データの記録 という興味深いサイトに巡り合いました。
(ホームページの冒頭から抜粋)
スマホの加速度センサーをリアルタイムに収集、結果を外部ファイルとして保存できるページを作ってみました。
コンセプトとしてスマホ側では完全にデータ収集に徹し、分析はCSVファイルを使ってPCのExcelなどで行いましょうというものです。
最初、全然意味が分かりませんでした。「スマホの加速度センサーをリアルタイムに収集、結果を外部ファイルとして保存できる」までは very good なわけですが、その後が「ページを作ってみました」になっている。
えっ? ページ? プログラムじゃないの? それ何処にあるの?
だいぶ経ってから、同じページをスマホで見ていて、何気なく測定ページへは以下のリンクからのURLをクリックしたら、やっと意味が分かりました。
なんと、スマホでURLをクリックした瞬間に、スマホがセンサーレコーダーに変身したのです。
まず、左側の画面が現れます。「測定開始」ボタンを押すと右側の画面になり、加速度(重力加速度なし)、加速度、回転の各センサーの値が目にも止まらぬ速さで記録されて行きます。
適当なところで「停止」ボタンを押して「データ・ダウンロード」ボタンを押せば、測定データがCSVファイルで保存できます。中々いいじゃないですか!
*ちなみに、実際にはダウンロードはしてなくて、ローカルに保存したデータをCSVファイルに書き出しています。
どうやって動いているのか調べてみると、ホームページを表示するプログラム( HTML5 )の中に、スマホのセンサーの値を読み込んだり、ファイルに保存したり、という命令が書いてあり、スマホのブラウザがそれを読み込んで実行しているんです。
素晴らしい!HTML5 にこんな力があるなんて知らなかった。これなら、Android Studio で開発するより、めっちゃ簡単じゃない?
PCのブラウザで、このホームページを表示し、Ctrl+U でソースコードを見てみると、プログラムは次の4つで構成されていることが分かりました。
1)https://www.fukushobo.com/misc/ sensor.html (ホームページ)
2)https://www.fukushobo.com/misc/js/ jquery-1.8.2.min.js (Javascriptのライブラリー)
3)https://www.fukushobo.com/misc/js/ s-engine.js (メインプログラム)
4)https://www.fukushobo.com/misc/css/ sensor.css (ホームページの装飾)
1)がホームページで、ここから2)~4)を呼び出しています.。3)がセンサーの値を読みだしたり、ファイルに保存したりする、メインプログラムの様です。
早速、1)~4)のソースコードをエディターにコピペし、4つのプログラムをPCに保存しました。
とりあえず、4つのプログラムが1個所に置いておけるように、1)を修正しておきます。
1 2 3 4 5 |
<script type="text/javascript" src="js/jquery-1.8.2.min.js"></script> <script type="text/javascript" src="js/s-engine.js"></script> <link rel="stylesheet" type="text/css" href="css/sensor.css"> |
1)のプログラムの冒頭部分です。
1 2 3 4 5 |
<script type="text/javascript" src="jquery-1.8.2.min.js"></script> <script type="text/javascript" src="s-engine.js"></script> <link rel="stylesheet" type="text/css" href="sensor.css"> |
呼び出し先の指定にある、js/ と css/ を削除しました。そして、sensor.html を index.html にリネームします。
さあ、これで s-engine.js を必要に応じて修正すれば、自分好みのセンサーレコーダーに改造できそうです。
後は、どうやってサイト公開するかです。
簡単にサイト公開する方法
サイト公開の方法を色々調べた結果、Github Pages という方法が一番簡単そうでした。
事前準備として、Github にアカウントを作り、PCに Git for Windows をインストール(Macの場合は不要です)しておきます。
具体例として、アカウントが cedro3 で、新規にWebに sensorフォルダー(repository)を作る場合を説明します。
1)https://github.com/ に cedro3 でログインして、「New repository」 をクリック。
2)Repository name に、sensor と入力し、「Create repository」 をクリック。これで、Webの sensorフォルダーが、 https://github.com/cedro3/sensor に作られます。
1 2 3 |
> git clone https://github.com/cedro3/sensor |
3)コマンドプロンプトで上記を入力し、Webの sensorフォルダー と同期させるPCのsensorフォルダー(clone)を作ります。PCの sensorフォルダーは、今作業しているディレクトリの直ぐ下に作られます。
4)エクスプローラー等を使って、PCの sensor フォルダーの中に、先程保存した4つのプログラムを入れます。
1 2 3 |
> cd sensor |
5)コマンドプロンプトで上記を入力し sensor フォルダーに移動します。
1 2 3 4 5 |
> git add –all > git commit -m “Initial commit” > git push -u origin master |
6)コマンドプロンプトで、上記を1行づつ入力し、PCの sensor フォルダーにあるプログラムを、Webの sensorフォルダーへ同期します。但し、これは初回のみ。
1 2 3 4 |
> git add –all > git commit -m “Update page” > git push -u origin master |
7)2回目以降(更新する場合)は、コマンドプロンプトで、上記を1行づつ入力して同期します。“Initial commit” が “Update page” に替わっただけです。
8)github の sensorフォルダーを開き「setting」をクリックします。
9)Github Pages という項目を見つけ、Source の None をクリックしてmaster branch を選択し、「save」ボタンを押します。これで、https://cedro3.github.io/sensor というURLで、サイト公開されました。
10)スマホで、https://cedro3.github.io/sensor を開くと、先程と同様に動きます。
ジェスチャーの設計
どんなジェスチャーが良いだろうかと色々考えていたら、ふと思い出したのが、Plam(パーム)のGraffiti (グラフティ)でした。
1996年~20005年頃、PDA(Personal Digital Assistant)という、スケジュール、ToDo、住所録、メモなどの情報を携帯する端末が流行っていました。
その中で、ダントツのシェアを誇っていたのが Palm。文字入力に Graffitiと呼ばれる一筆書きを採用することで、非力なハードウエアでも素早い入力と高い認識率を実現していました。
私も使っていましたが、Graffiti は直ぐ覚えられ、素早い入力が出来たような記憶があります。
では、懐かしのPlamのGraffiti を見てみましょう。
これが、Palm の Graffiti です。どの文字も一筆書きでシンプルになっていますね。今回は、これをそのままパクることにします(笑)。
ということで、今回のジェスチャーデータは、スマホを手にもって、空中で Graffiti を書いた時の、加速度センサーのデータを使おうと思います。
実際にデータを取ってみる
それでは、実際にジェスチャーデータを取ってみます。
これが、「A」をジェスチャーした時のスマホのセンサーのCSVデータです。なお、1行目は説明のために追加したもので、実際はありませんのでご注意を。
一番左の列から、時刻(UNIX time)、加速度(重力加速度なし)のx,y,z 、加速度のgx,gy,gz 、回転のa,b,g と並んでいます。
行数は全部で88行、測定のトータル時間は1.67秒なので、1行が約0.02秒に相当します。
測定開始ボタンを押してから動かすまではタイムラグがありので、最初は0のデータが結構並んでいますね。
ここで1つ問題が出て来ます。文字によって一筆書きのストロークに違いがあるので、ジェスチャーに掛かる時間も変化します。従って、CSVファイルの行数も変化するわけです。
ところが、Neural Network Console は、CSVファイルの行数が一定でないと受付てくれません。ここをどうするか。
まずは、実態把握からということで、実際のジェスチャーに掛かる時間を計測してみます。
計測の方法は、スマホを水平に持って、「測定開始」ボタンを押してジェスチャーを開始し、ジェスチャーが終わったら「停止」ボタンを押します。これをアルファベット 26文字について、それぞれ何行掛かるのか、3回平均を取ってみました。
結果、アルファベット26文字の平均は102.5行で、一番短いのは「I」の73.7行、一番長いのが「B」の130.7行でした。さて、この差をどう埋めるか。
直感的に考えて、CSVファイルを120行で固定することにしました。そして、120行未満で測定が終わった場合は120行まで0データを追加する。120行超えの場合は120行で計測を打ち切る。
一番長い「B」の130.7行を120行で打ち切っても全体の10%未満なので、さほど影響はないだろうと判断しました。
センサーレコーダーの改造
それでは、Neural Network Console のジェスチャーデータ収集のために、センサーレコーダーを改造します。
改造点は、下記4つです。
1)CSVファイルは必要な項目のみ
2)計測を120行で打ち切る処理の追加
3)計測が120行未満の場合の処理の追加 + 正規化
4)保存するファイル名の修正
順に見て行きます。
1 2 3 4 |
//キーの値をCSV用にリスト化 finalVal += localstragekey +","+ d_acc_x +","+ d_acc_y +","+ d_acc_z +","+ d_acc_gx +","+ d_acc_gy +","+ d_acc_gz +","+ d_rr_a +","+ d_rr_b +","+ d_rr_g +'\n'; |
CSVファイルのフォーマットを指定している部分です。余分なものを外します。
1 2 3 4 |
//キーの値をCSV用にリスト化 finalVal += d_acc_x +","+ d_acc_y +","+ d_acc_z +'\n'; |
加速度(重力加速度なし)のみ残し、後は削除すればOKです。
1 2 3 4 5 6 7 8 |
//function function exportcsv(){ var finalVal = ''; for(var i = 0; i < localStorage.length ; i++) { |
CSVファイルを作成するためにループを廻している部分です。120行で計測を打ち切るようにします。
1 2 3 4 5 6 7 8 |
//function function exportcsv(){ var finalVal = ''; for(var i = 0; i < 120 ; i++) { |
localStorage.length を120に置き換えるだけです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
if(localStorage.getItem(localstragekey)){ var d = JSON.parse(localStorage.getItem(localstragekey)); d_acc_x = d.acc_x; d_acc_y = d.acc_y; d_acc_z = d.acc_z; d_acc_gx = d.acc_gx; d_acc_gy = d.acc_gy; d_acc_gz = d.acc_gz; d_rr_a = d.rr_a; d_rr_b = d.rr_b; d_rr_g = d.rr_g; } |
CSVファイル作成のために、ローカルストレージからデータを読み込んでいる部分です。(120行未満で)読み込むものがなくなった場合の動作を追加します。また、Neural Network Console で読み込むデータは、概ね―1.0~+1.0の範囲である必要があるためその修正(正規化)を行います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
if(localStorage.getItem(localstragekey)){ var d = JSON.parse(localStorage.getItem(localstragekey)); d_acc_x = d.acc_x / 10; d_acc_y = d.acc_y / 10; d_acc_z = d.acc_z / 10; d_acc_gx = d.acc_gx; d_acc_gy = d.acc_gy; d_acc_gz = d.acc_gz; d_rr_a = d.rr_a; d_rr_b = d.rr_b; d_rr_g = d.rr_g; }else{ d_acc_x = 0; d_acc_y = 0; d_acc_z = 0; } |
else 文を追加して、読み込むデータがなくなったら、0を代入するようにします。
また、加速度(重力加速度なし)のデータを読み込む部分を10で割って正規化しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// Display the month, day, and year. getMonth() returns a 0-based number. var date = new Date(); var year = date.getFullYear(); var month = ("0"+(date.getMonth() + 1)).slice(-2); var day = ("0"+date.getDate()).slice(-2); //set csv-data to a-tag on html var download = document.getElementById('download'); download.setAttribute('href', 'data:text/csv;charset=utf-8,' + encodeURIComponent(finalVal)); download.setAttribute('download','sensor'+ year + month + day +'.csv'); |
CSVファイルの名前を指示している部分です。ファイル名が sensor+年+月+日では長くて使いづらいので修正します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
// Display the month, day, and year. getMonth() returns a 0-based number. var date = new Date(); var year = date.getFullYear(); var month = ("0"+(date.getMonth() + 1)).slice(-2); var day = ("0"+date.getDate()).slice(-2); var hours = ("0"+date.getHours()).slice(-2); var minutes = ("0"+date.getMinutes()).slice(-2); var seconds = ("0"+date.getSeconds()).slice(-2); //set csv-data to a-tag on html var download = document.getElementById('download'); download.setAttribute('href', 'data:text/csv;charset=utf-8,' + encodeURIComponent(finalVal)); download.setAttribute('download','g'+ hours + minutes + seconds +'.csv'); |
hours, minutes, seconds の変数を追加して、ファイル名は g +時+分+秒 にしました。
なお、改造したプログラムを含む4本のプログラムは、https://github.com/cedro3/gesture にあります。動かしてみたい方は、スマホで、https://cedro3.github.io/gesture/ をクリックしてみて下さい。
後編に続きます!
では、また。