ラジコンの視界をスマートグラスで

子供の誕生日プレゼントで、ラジコン戦車を買いました。

スマートグラスを使い、ラジコン戦車に乗っているような視界を見ながら、操縦できるようにします。

撮影映像を見ながらの操縦

スマートグラスと「MOVERIO」は、アプリを使ってドローンの撮影映像を目の前で確認できるという、特長紹介がされています。

ドローンは持っていませんが、たまたま子供がラジコン戦車を誕生日に欲しがっていたので、これを使って擬似体験をしようと思います。

・・・ただ、技術研究というより、もう95%遊びみたいな感覚で、精神的につらかったです。

システム構成

前回の構成に、ラジコンが加わっただけです。

システム環境やコードなどは、前回の記事をご確認ください。

ラジコンにWebカメラ搭載

たまたまですが、簡単に装着できました。

Webカメラの有線が気に入らない場合、無線のWebカメラに置き換えたほうがよいでしょう。

 

あとは、前回と同様の手順でサーバーを立ち上げ、ノートパソコンとスマートグラスのブラウザで、カメラ映像を表示します。

くっ・・・楽しい

戦車を操縦しながら、戦車の視界を見ることができます。

この戦車、砲身から球を撃てるので、戦車の視界で狙いを定め、発砲することもできます。

的を用意して、ゲームを作れます。

※子供のスマートグラスの利用は、年齢制限と時間制限に十分ご注意ください。

作業向きのスマートグラス+AR

スマートグラス+AR(視界の拡張)を、何か操縦する系統のゲームで利用を考えると、臨場感がVRに劣り、いまいちでしょう。

スマートグラス+ARである良さは、操縦している対象と、その対象の視界を同時に見れること。

ゲームより、物販作業とか救出作業とかのほうが向いています。

 

スマートグラスを購入して、ラジコンで遊んで終わった・・・という結果にならないよう、需要ある開発を考えていきたいです。

スマートグラス「MOVERIO」で視界の拡張

スマートグラス「MOVERIO」で、視界の拡張を試してみます。
別アングルの映像を、同時に見られるようにしてみましょう。

現実と俯瞰映像を同時に見るテスト

私が今回テストしたのは、ボールを投げながら、俯瞰映像で上からボールの位置を同時に見るというものです。

ちなみに、白いボールに近づける「ボッチャ」というスポーツを、テスト題材としています。

ボッチャは俯瞰映像じゃないとボールの距離が分からないので試してみました。ちょっとサンプルとしてはマニアックかも。

ハード構成

Windowsノートパソコン・・・CORE i7
Webカメラ・・・LOGICOOL  C270
スマートグラス・・・MOVERIO BT-300

システム構成

今回のテスト内容だけならWebRTCを使うのが良いような気がします。

しかし、下記のような構成をすでに構築したことがあるので流用しています。

ノートパソコンをサーバーにして、Webカメラの映像をスマートグラスに飛ばします。HTMLとCSSとJSだけのWeb技術者にとってハードルの低い構成です。

ディレクトリ構成は以下になります。

test.jsにサーバープログラムが書かれています。
一部、他でも共用しそうなプログラムを、common.jsに切り分けています。

testフォルダ内にあるHTMLがカメラ映像の入出力をするWebアプリです。

node_modulesフォルダと、package.jsonは、Node.js関係のもの。説明は省略。

サーバー側プログラム

まずはサーバー側のコードを掲載します。Node.js、Express、Socket.ioのインストールは情報も多いので割愛します。

環境
Windows10
Node.js 6.11.0
Express 4.15.3

サーバー本体 test.jsのコード

var TCP_PORT = 3000,
    DIRECTORY = 'test',
    express = require('express'),
    app = express(),
    http = require('http').Server(app),
    io = require('socket.io')(http);

var COMMON = require('./common.js');

var init = function () {
  app.use(express.static(DIRECTORY));
  http.listen(TCP_PORT, function(){
    console.log(COMMON.getIP() + ':' + TCP_PORT + ' でサーバーを起動');
  });
  setIo();
},

//ソケットIO設定
setIo = function(){
  io.on('connection',function(socket){
    socket.on('camera',function(data){
      io.emit('dataURL',data);
    });
  });
};

init();

サーバーを立ち上げて、Socket.ioで画像のdateURLを送受信する仕組みです。

8行目で読み込んでいるcommon.jsのコードは以下です。

//ローカルIPアドレス取得
exports.getIP = function(){
  var os = require('os'),
      ip,
      interfaces = os.networkInterfaces();

  var getIPv4 = function(){
    interfaces[dev].forEach(function(details){
      if (details.family === 'IPv4' && details.address.indexOf('192.') > -1){
        ip = details.address;
      }
    });
  };

  for (var dev in interfaces) {
    getIPv4(dev);
  }
  return ip;
};

自分の使っているローカルIPをアドレスを、コンソールログで表示させるだけのプログラムです。切り分けなくても良いですし、なくても良いです。

フロント側プログラム

続いてHTML5を使ったフロント側のコードを掲載します。

Webカメラの映像を取得してサーバーに送るcamera.html

<!doctype html>
<html>
<head>
<title>Camera</title>
<script src="/socket.io/socket.io.js"></script>
<style media="screen">
body {
  background-color: #000;
  text-align: center;
}
video {
  display: none;
}
</style>
</head>
<body>
<video id="webCamera" width="640" height="480" autoplay></video>
<canvas id="canvas" width="320" height="240"></canvas>

<script type="text/javascript">
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia;
window.URL = window.URL || window.webkitURL;
var socket = io(),
    video = document.getElementById('webCamera'),
    canvas = document.getElementById('canvas'),
    canvas_w = canvas.clientWidth,
    canvas_h = canvas.clientHeight;

navigator.getUserMedia({video: true, audio: false},
  function(stream){
    console.log(stream);
    video.src = window.URL.createObjectURL(stream);
    video.addEventListener('timeupdate', webCameraTimeUpdate);
    video.play();
  },
  function(err){
    console.log(err);
  }
);

function webCameraTimeUpdate(){
  var ctx  = canvas.getContext('2d');
  ctx.drawImage(video,0,0,canvas_w,canvas_h);
  var data = canvas.toDataURL();
  socket.emit('camera', data);
}
</script>
</body>
</html>

640px幅でWebカメラから動画を取得して、320pxに縮小しています。
21行目、22行目は最新のChromeで動かすときは必要ありませんが、「MOVERIO」など、古いブラウザで動かしたいときは必要です。

サーバー映像(連続した静止画)を受信するview.html

<!doctype html>
<html>
<head>
<title>view</title>
<script src="/socket.io/socket.io.js"></script>
<style media="screen">
  body {
    background-color: #000;
    text-align: center;
  }
</style>
</head>
<body>
<img id="videoImg" alt="" width="640px" height="480px;">
<script>
  var socket = io(),
      videoImg = document.getElementById('videoImg');

  socket.on("dataURL", function(data){
    videoImg.setAttribute('src', data);
  });
</script>
</body>
</html>

軽量化していた320px幅の画像を、640pxに戻しています。

サーバー起動とブラウザ立ち上げ

コマンドプロントを立ち上げ、サーバーのディレクトリ(私の場合はC:\CAMERA)に移動します。

を打ち込みEnter。サーバーが起動します。

そのあとブラウザでcamera.htmlを読み込みますが、現在のChrome60だとhttpsではない通信で、カメラをブラウザから起動できません。

http://192.168.X.X:3000/camera.html

というURLではだめなので、https環境を用意するか、

http://localhost:3000/camera.html

という、ローカルホストで読み込む必要があります。

テストであればローカルホストで十分です。

Webカメラの映像が、ブラウザに映し出されます。

正確にはWebカメラの映像を、HTML5のCanvasに転写したものが表示されています。若干カクカクしていると思います。

なお、カメラが複数あるときは、右上のカメラアイコンで、別のカメラを選択してください。

スマートグラスの準備

スマートグラス「MOVERIO」を着用し、ブラウザでview.htmlを開きます。

http://192.168.X.X:3000/view.html

IPアドレスは、コマンドプロントで表示されたものを入力。

目の前にカメラの映像が表示されると思います。

投球してみよう!

カメラを任意の場所へセットすれば準備は完了です。ボールを投げてみます。

・・・。

なんか、おもしろい。

そして不思議な体験です。

スマートグラスに映す必要性があるか問われると疑問ですが、近未来の感覚を体験できます。

ただ、「MOVERIO」は正面に映像が見えるタイプのスマートグラスなので、その映像を避けながら現実を見ないといけません。映像を小さくして、端っこに表示しても良いでしょう。

思ったより遅延しない

映像の遅延は0.86秒。映像の解像度を抑えているため、1秒以内に収まっています。通信環境によって遅延時間は変わると思います。

今回のような投球の映像であれば、リプレイを見ているような別のメリットがあるので、逆に遅れて良いような気がします。

映像はカクカクしているので、精密な映像を求めるときは、この構成では無理があるでしょう。

汎用性の高いWebアプリ

今回のようなブラウザで動くWebアプリは、汎用性が高いです。
デバイスに依存しません。(本当は依存しますが・・・)

ブラウザを搭載したスマートグラスであれば「MOVERIO」じゃなくても動作しますし、スマートグラスに限らず、iPhoneでもAndroidスマートフォンでも動作します。

視界の共有もできる

また、今回テストした構成とは逆で、スマートグラスとパソコンのHTMLを入れ替えて読み込むことで、スマートグラスのカメラの映像をパソコンに送ることができます。

スマートグラスをかけた人の視界を遠隔で共有できます。これはすでにフィールド業務(機械・システムの運転)で活用事例があります。

視界の拡張の利用場面

今回のサンプルの利用場面を考えてみます。

スポーツしながら別アングル映像を見るという使い方より、スポーツ観戦しながら利用する方が適しています。
選手の表情のアップや、自席から見えないアングルの映像を見られるとおもしろいです。

 

他にも、防犯で有効活用が期待できます。

監視カメラの映像を視界の隅に映し、ガードマンに着用させるのが良いかもしれません。

死角のない警備ができそうです。

 

また、赤ちゃんのうつ伏せ寝を監視も、できるかもしれません。

保育士の人手不足で、もうスマートグラスで視界を拡張しないと、子供を見切れないのでは?と、思うことはあります。

 

あとは、背面カメラ。

子供を連れて自転車で移動するときの、安全確保で利用できれば。

親が先頭を走って誘導すると、後ろをついてくる子供が見えません。
頻繁に後ろを振り向いて確認しますが、その間、前方を見ていないので危険です。

スマートグラスで後ろの映像が分かる、バックミラーみたいな使い方ができれば良いかもしれません。

自転車用のサイドミラーがありますが、見た目の問題で、装着に抵抗があります。

・・・スマートグラスも、まあ、装着に抵抗があるのですが。

 

いろいろと思いつきます。

次回は、Webカメラをラジコンに搭載し、スマートグラスで映像を見てみます。

「MOVERIO」スポーツ観戦の可能性

最近、画像認識技術の勉強をしています。画像認識とスマートグラス(メガネ)との相性は抜群で、個人的には言語や知識、障害の差を埋めるアクセシビリティ向上ツールとして可能性を感じています。

自分に必要な情報を、自分の知っている言語で、自分の状況に応じ、現実と重ねて見る。素晴らしい体験です。

私はスマートグラスの中で、もっとも現実と情報を重ね合わせて違和感がないと感じたEPSONの「MOVERIO BT-300」を所持しています。

AppleやFacebookがスマートグラスの開発に着手している噂が流れていますが、日本のEPSONに頑張ってもらいたい!

今回はこの「MOVERIO」について言及したいと思います。

「MOVERIO」の可能性

「MOVERIO」をかけて外を出回るには・・・まだ勇気がいります。

ファッションに溶け込むデザインではないので、現段階で一般普及は難しいでしょう。

ただ、スタジアムや博物館などの限定された空間で、お客さんの体験に付加価値を与えたり、補助したりする使われ方は有効です。

ちょっと導入単価が高いので、数十人限定のイベントで使用したり、もしくは、情報をより必要とする外国人、障害者の補助ツールとして常備する使い方になると思います。

最新の「BT-350」の方が、商用利用を想定した作りとなっています。

スポーツ観戦でのメリット

「MOVERIO」の利用場面は、いくつか思い当たりますが、試合から目が離せないスポーツ観戦は、相性が良いと思います。

アスキーに「スポーツ観戦をもっと楽しむ! スポーツ好きのための「MOVERIO」活用術」が掲載されており、興味深く読みました。

記事から引用します。

自分が視線を向けている方向にチームや選手の情報を表示できるため、スマートフォンのように、手元の画面に向いたりグランドに向いたりと視線の方向を変える必要がなく、試合に集中し続けられた

情報と生の試合を重ねて見られることが「MOVERIO」のメリットです。

スマートフォンを観戦に利用すると、視線の方向に加え、焦点距離が違いすぎ、手元の情報と同時に試合を見ることはできません。

そもそも生で観戦しているのに、手元を見ていると悲しくなります。

運動会で、ビデオカメラの小さい画面を通して子供の走りを見る・・・あの悲しい感覚に近いです。・・・生で見たい。

手元を見なくても情報を得られる観戦体験は、「MOVERIO」のようなスマートグラスにしかできない、大きな利点です。

ハンズフリーも魅力

両手がふさがらないことも、「MOVERIO」の大きなメリットだと思います。

情報を得ながら、拍手したり、飲食したり。

コントローラーをポケットに入れるか、首からぶら下げている状態であれば、ハンズフリーを実現できます。

さらに首や手のジェスチャー操作などで、コントローラーを持たなくても操作できるアプリがあれば、もっと快適になると思います。(そういUIの開発が必要です。)

ネットラジオの併用が最強

アスキーの記事では「NHKネットラジオ」の試合中継を聞きながら、「MOVERIO」で観戦する楽しみ方が紹介されています。

「MOVERIO」は高コントラストで、はっきり情報を見られるのが良いですが、反面、情報表示量を抑えないと、目が疲れます。

なので、聴覚を使うラジオとの組み合わせは最強です。

ゴールボールでミニFMラジオと映像を組み合わせた観戦を体験したことがあります。これが非常に分かりやすい。

AR(現実拡張)といった新しい視覚体験ができる「MOVERIO」ですが、視覚に詰め込まず、うまく音声に分散したほうが、より良い観戦を実現できると思います。

スマートグラス観戦の今後に期待

スポーツのデータ化が進み、得られる情報も増えています。

さらに、音声ガイドの自動生成や手話CGへの変換などの、スポーツ観戦のアクセシビリティ研究も進んでいます。

スマートグラスと掛け合わせることで、観戦環境が大きく改善されそうです。

アクセシビリティの話を先にしましたが、もちろん一般的な観戦の付加価値も、格段に上がるでしょう。

専用のアプリを開発し、運用体制を整えれば、得点や時間のような試合情報を、観客の目の前に表示させることもできますし、リプレイや別アングルの映像も映し出せます。

試合情報以外でも、例えばARで時速260kmのテニスのサーブを体感できたりすると、面白そうです。(見えないかも)

スマートグラスの商用利用研究で、一歩先を行く「MOVERIO」のおかげで、サービスの可能性が広がりました。

未来が楽しみです。

 

openCVで人物特定の分類器を自作

前回、人の顔を認識するテストに引き続き、今度は人物を特定するための分類器を自作したいと思います。

「この顔が誰か?」が分かれば、開発の可能性が広がります。

人物特定の目標

いきなり高度な特定は難しそうなので、簡単な目標を立てます。

斜め45度を向いている少年の画像を機械学習させ、分類器を作り、似たような角度で写っている少年の画像を認識させようと思います。

分類器自作の流れ

正解画像と不正解画像をあわせて10,000枚くらい用意して、機械にひたすら学習させるようです。

そこまで頑張れないので、1枚の正解画像を変形させ、正解画像を量産する方法を取ります。

具体的な分類器作成の流れは、「OpenCVで物体検出器を作成する⑤ ~createsamples~」を、参考とさせて頂きました。

cleatesamplesが見つからない!?

参考サイトを見ながら、正解画像を量産させる「opencv_createsamples.exe」を実行させようとしたのですが、PC内を検索しても見つかりません。

他にも「opencv_calib3d2411.dll」などが見つからず。

ファイル名からの推測ですが、OpenCV2.4.11環境を用意しないとダメそうです。

Anacondaが活躍

早速、仮想環境を増やすことになりました。

AnacondaでPython2.7+OpenCV2.1.11環境を作ります。

思いのほか、備忘録が役立ちました。

で、opencv: 2.4.11がインストールされます。(2017/8月時点では)

作業ディレクトリを用意

分類器を作成するディレクトリは、下記のような構成になっています。

正解画像を量産

切り抜いた少年の画像をposフォルダに置きました。

これを「cleatesamples」で量産します。やり方は前述の参考サイトをご確認ください。

7,000枚以上が理想らしいですが、とりあえず50枚しか作りません。

私のディレクトリ構成だと、コマンドプロントでC:\traincascadeに移動して、下記の命令を実行します。

・・・。

正解画像が変形しながらが量産され、C:\traincascade\vecに「1.vec」という正解特徴データが生成されます。

不正解画像の用意

続いて、negフォルダに不正解画像を用意します。

何でもよいようですが・・・何でもよいと言われると、逆に困ります。

適当に、別人3名と、犬、ライオン、フクロウ、カエル、テントウムシを用意しました。

3,000枚以上が理想らしいですが・・・8枚で許してもらいます。

コマンドプロントで不正解画像一覧を作ります。

negフォルダにnglist.txtができました。

分類器の作成

いよいよ分類器の作成です。

分類できる手ごたえが皆無なのですが、このままやってみましょう。

コマンドプロントで

を、実行します。

・・・。

大量の学習データがあると時間がかかるのですが、動き出して26秒で完了しました。

C:\traincascade\cascade\trained_dataに、分類器のxmlが生成されます。

10個できましたが、cascade.xmlしか使わなそうです。

cascade.xmlの容量は5KB。・・・軽い。

自作分類器で顔認識のテスト

それでは少年の顔を特定できるか?自作分類器を試しましょう。

Python 3.6.1+OpenCV 3.3.0の環境に戻し、下記Pythonファイルを実行します。

import cv2

# 自作Haar-like特徴分類器の読み込み
face_cascade = cv2.CascadeClassifier('traincascade/cascade.xml')

# イメージファイルの読み込み
img = cv2.imread('img/test9.jpg')

# グレースケール変換
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 顔を検知
faces = face_cascade.detectMultiScale(gray)
for (x,y,w,h) in faces:
    # 検知した顔を矩形で囲む
    cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
    # 顔画像(グレースケール)
    roi_gray = gray[y:y+h, x:x+w]
    # 顔画像(カラースケール)
    roi_color = img[y:y+h, x:x+w]

# 画像表示
cv2.imshow('img',img)

# 何かキーを押したら終了
cv2.waitKey(0)
cv2.destroyAllWindows()

4行目で自作分類器を読み込み、7行目で認識させたい画像を読み込みます。

まずは元画像でテスト

正解画像作成の元ととなった画像を読み込んでみます。

これはさすがに認識できなければおかしいはずです。

良かったです。少年を認識してくれました。

変なところも認識していますが・・・不正解画像の学習が、テントウムシとか8枚だけなので、仕方ないでしょう。

表情が違う画像でテスト

そして今回の目標。

ちょっと表情が違う別の画像を認識できるか試します。

・・・。

何も反応なし。

こんな軽い学習では、やっぱり無理でした!

元画像を変形してテスト

せめて、元画像をちょっと変形させたものくらい、認識してほしいです。

若干の回転と拡大をして、顔認識テスト実行・・・

そっちかよ!

少年は認識されませんでしたが、誤認はされました。

・・・いったいどれだけの精度なんでしょう!?

正解画像を回転・拡大テスト

この分類器は、回転や拡大に弱いのかもしれません。

正解画像の少年を、回転させたり、拡大縮小させてみます。

拡大は余裕で、回転も縮小も、思った以上に認識してくれます。

・・・いや、違和感があるくらい、認識しすぎです。

白背景をやめてみる

少年に、工場見学へ行ってもらいます。

これで顔認識を実行すると・・・

やはり、一気に認識されなくなりました。

少年の変形よりも、画像全体の複雑さが、認識に影響を及ぼすようです。

人物特定の分類器作成には根性と精神衛生が必要

今わかっていることは2つ。

人物特定の分類器を自作するには、大量の画像に向き合える根性が必要です。
数枚の正解画像で、なんとかなるものではありません。

そしてもう一つ、ひたすら同じ人の顔を見ていると、つらくなります。

仮に7,000枚のおじさんの画像を学習させるとしたら、精神的にまいるでしょう。

人の顔に限らず、例えば虫が嫌いな人に、虫分類器を依頼することは酷です。

開発プロデューサーは、分類器作成を依頼するなら、その人の好き嫌いを十分配慮したほうがよいです。本当に。

 

いろんな意味で、分類器自作は難しい!

OpenCV3で顔認識 精度をテスト

前回なんとかPython3+OpenCV3の環境を用意しました。

さっそく顔認識のテストを行います。果たしてどれだけの精度か?

顔認識の仕組み

まずは、顔認識の仕組みをおおざっぱに理解したいと思います。

顔を認識するには、顔かどうか分類する特徴データが必要となります。この特徴データを「分類器」と呼ぶようです。

分類器と照らし合わせて、顔かどうか判断します。

分類器を作るために、人間の顔の特徴を機械に学習させないといけません。
これを機械学習と呼びますが、顔のようなメジャーなものは、学習済みデータが手に入ります。

使用する分類器

今回テストで使う分類器は、OpenCVデフォルトの2つです。

  • haarcascade_frontalface_default.xml・・・正面顔
  • haarcascade_eye.xml・・・目

PCで「haarcascade_frontalface_default.xml」を検索すると、どこかで見つかるかと思います。

分類器は他にも、全身や笑顔などが用意されています。

感情取得は面白そうです。精度次第ですが・・・。

ディレクトリ構成

顔認識のテストを始めます。

前回用意した「C:\FACE」内に下記の構成でフォルダとファイルを用意します。

  • haarcascades・・・分類器のフォルダ
  • img・・・テスト用の画像フォルダ
  • rectangle.py・・・顔認識して四角で囲うプログラム

分かりやすいので、分類器のフォルダ「haarcascades」を、C:\FACEにコピーしてきました。
使用するのは、顔正面と目の分類器だけです。

テスト画像の用意

imgフォルダには、テストする画像を6枚いれました。

GATAGフリー画像・写真素材集より、パブリックドメインのものを使わせて頂きます。

顔認識のPythonプログラム

rectangle.pyは、「OpenCVを使った顔認識」で紹介されているコードを使わせて頂きました。

私のディレクトリ構成に書き換えただけですが、分かりやすいように掲載します。

import cv2

# Haar-like特徴分類器の読み込み
face_cascade = cv2.CascadeClassifier('haarcascades/haarcascade_frontalface_default.xml')
eye_cascade = cv2.CascadeClassifier('haarcascades/haarcascade_eye.xml')

# イメージファイルの読み込み
img = cv2.imread('img/test6.jpg')

# グレースケール変換
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 顔を検知
faces = face_cascade.detectMultiScale(gray)
for (x,y,w,h) in faces:
    # 検知した顔を矩形で囲む
    cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
    # 顔画像(グレースケール)
    roi_gray = gray[y:y+h, x:x+w]
    # 顔画像(カラースケール)
    roi_color = img[y:y+h, x:x+w]
    # 顔の中から目を検知
    eyes = eye_cascade.detectMultiScale(roi_gray)
    for (ex,ey,ew,eh) in eyes:
        # 検知した目を矩形で囲む
        cv2.rectangle(roi_color,(ex,ey),(ex+ew,ey+eh),(0,255,0),2)

# 画像表示
cv2.imshow('img',img)

# 何かキーを押したら終了
cv2.waitKey(0)
cv2.destroyAllWindows()

4行目、5行目で分類器の読み込み。相対パスで読み込んでいます。

8行目でテスト画像の読み込み。ここのファイル名を書き換えながら、テストをしていきます。

テスト1 正面を向いた西洋人

まずは、顔認識が容易そうな画像から。

私の仮説(思い込み)では、西洋人の機械学習量の方が多く、認識されやすいのではと考えています。

さらに背景も白単色。服もシンプルな画像で実行。

おお!お?

顔も目も、すべて認識しています。

しかし、3か所顔ではないところを誤認しています。

けっこう判定がゆるいのか?

テスト2 赤ちゃん

続いて、顔の特徴が違う赤ちゃんを認識できるかテストです。

認識できれば、赤ちゃんが寝返りで窒息しないよう、見守りで使えそうです。

お、認識できました。・・・あれ?

緑の四角は目なのですが、赤ちゃんに4か所目が認識されてます。

お母さんも3か所。

通常は1つの顔に、目は2つしかないことを、機械に教えてあげないといけないようです。

テスト3 東洋人

次に、日本では実用的な、東洋人の顔認識テストです。

顔はだいたい認識されています。目は、けっこう開いていないと認識されないようです。

右手前の男の子の顔が認識されていません。
正面の女の子の手が邪魔で、首を傾けていますが、これくらいで認識精度は落ちるようです。

また、真ん中後ろの女性と、一番右の女性は、顔が2回認識されています。

テスト4 背景ごちゃごちゃ+犬

機械に厳しくしていきます。

今までと違い、背景がごちゃごちゃした画像で試します。

さらに犬までいるので、誤認だらけになってしまいそうですが・・・

あれ?予測の逆。

判定がシビアになり、認識された顔の数が減り、誤認はゼロ。

目は一つも認識されない事態に。

顔一つあたりの解像度が低すぎたかな?

テスト5 横顔

今度は横顔をどれだけ判断できるかテストします。

いつでも正確に正面を向いてくれるほど、人間は甘くありません。

おっ!正面顔の分類器を使っているのに、意外といけます。

お母さんはさすがに無理ですが、女の子はこの角度でも認識されました。

男の子も目をつむっているのに、一つは目として認識されています。

テスト6 見上げた横顔

先ほどの女の子と同じくらいの横顔で、見上げた状態の顔認識テストです。

心霊写真検出!?

正面顔の分類器に、この画像の認識は酷だったのでしょう。

横顔分類器に変更します。

rectangle.pyの4行目を「haarcascade_profileface.xml」に変更。

あれ?

何も認識しない。プログラムの問題?

検証のため、再びテスト5の女の子で確認。

認識します。盛大に誤認もします。

ということで、見上げた顔が認識されにくいことになります。

テスト3でも感じましたが、傾いた顔の認識が弱いです。

精度を求めるのは簡単ではない

遊びでは良いですが、OpenCVデフォルトの分別器をそのまま使って顔認識は厳しい印象です。

精度を求める場合、深層学習(ディープラーニング)の分野まで進む必要があるかもしれません。

人間ってすごい

小学生みたいな感想ですが、今回のテストで感じたことは、人間ってすごい!

視覚情報をリアルタイムで処理して、人の顔を認識するというのは、途方もなく高度な処理なんだと思います。

人間のようなリアルタイム高精度処理はできませんが、次回、Webカメラを使った動画の顔認識を試してみます。
やっぱり分類器自作を試みます。

Webカメラによるリアルタイム顔認識は、他サイトのコードを持ってきただけで終わってしまったので。

Python3+OpenCV3 インストールメモ

これからの時代を生き抜くため、かねてから必要性を感じていた画像認識に手を出しました。

Pythonも書いたことがないのに、OpenCVで画像認識を体験したくなった初心者の、環境構築 備忘録です。

同じようにハマった初心者の助けになれば・・・

■環境・バージョン

Windows10
Anaconda 4.4.0
Python 3.6.1
OpenCV 3.3.0

■Anacondaのインストール

簡単にpython3系列とOpenCV3を導入する」を参考とさせて頂きました。

簡単・・・に惹かれ。

「作業手順」の項目を見ながら、まず「Anaconda」をインストールします。

依存ライブラリの解決は心が折れそうなので、パッケージ化された「Anaconda」を使った方が良さそうです。

■仮想環境の作成

「Anaconda」のインストールが終わったら、仮想環境の作成を行います。

仮想環境ごとにpythonのバージョンを選べるので、(現時点では新しい)3.6を指定し、環境名は「py36」としています。

コマンドプロントで

と、入力して「Enter」。何か聞かれたら「y」で肯定。

仮想環境の作成が完了したら、

で、仮想環境が立ち上がります。

コマンドプロントに括弧で環境名が表示されます。

 

なお、仮想環境から抜けるときは、

のようです。

※この記事はWindowsの場合です。

■OpenCVのインストールがうまくいけば

あとはOpenCVのインストールのみ。

コマンドプロントで、

と、たたけば良いだけのはずですが・・・。

■テスト用Pythonファイルで確認

インストールが成功しているか、テストします。

OpenCVをPythonで読み込んで、OpenCVのバージョンを表示させるだけの、テスト用Pythonファイルを作ります。

私の場合は、顔認識をさせる予定なので「FACE」というフォルダをCドライブ直下に作成し、そこに、「run.py」というファイルを作りました。名前は任意です。

import cv2 # OpenCV読み込み
print(cv2.__version__) # OpenCVバージョン表示

OpenCV3を読み込むのに「import cv2」?でも、これは正しいようです。

それではコマンドプロントで、実行してみましょう。

で移動して

で実行。

バージョンが表示されれば無事成功です。

無事成功しない場合

私は無事では済まず、「cv2が見つからないよ」というエラーに悩まされました。

パスが通ってないのかな・・・?解決には至らず、別の手段をとります。

pipでOpenCVをインストール

「pip」というパッケージ管理ツールを使ってインストールします。

「Anaconda」で管理していたはずなので、「pip」の併用はまずいような気もしますが、もう進みます。

OpenCV 3(core + contrib)をWindows & Python 3の環境にインストール・・・」を参考とさせて頂きました。

pipでopencv3.3をインストールしてみましょう。

非公式?のWindows用Python拡張パッケージ集から、「opencv_python-3.3.0+contrib-cp36-cp36m-win_amd64.whl」を選んでダウンロード。

コマンドプロントでダウンロードしたフォルダに移動し、

で、インストール。

さあ、これでまたC:\FACEに戻って、

テストpythonの再実行。

・・・。

あれ。

エラーが変わった・・・。

numpyをアップグレード

エラーが変わっただけでも、前進した喜びがあります。(本当に前進しているか分かりませんが)

エラーの内容は、

「numpy」という、また新しい言葉が出てきました。数値計算ライブラリのようです。

調査したところ「numpy」のアップグレードで対処できるかもしれません。

コマンドプロントで、

と実行。

バージョン1.12.1から1.13.1へアップグレードされました。

インストール成功!

飽きるほどたたきましたが、C:\FACEに戻って、

実行。

・・・。

と、応答が!

ようやくOpenCVを読み込み、バージョンが表示されました。

 

ここから顔認識までも、またいろいろハマったのですが、今回はここまで。

3Dプリンターで失敗経験を蓄積

使えるモノを作るには、何度も失敗を繰り返す必要があります。

そのため、高速で何度も失敗できるように、近くに3Dプリンターを置いています。

5127回の失敗

ダイソンのサイクロン掃除機が完成するまで、5127回の失敗作があったと聞きます。

繰り返しのプロトタイプ開発で破産寸前まで追い込まれたジェームズ・ダイソンさん。その失敗を繰り返せる精神を尊敬します。

私は3回くらいの失敗で、けっこう堪えてしまうのですが・・・。

 

何はともあれ多くの失敗は、良いプロダクトを作る上で必要なことで、さらに限られた時間と資金しかないのなら、高速で失敗できる環境は必須かと思います。

失敗できる環境づくりの失敗

3Dプリンターが個人でも持てる良い時代になりました。

ただ、3Dプリンターは立体物を簡単に印刷きる周辺機器・・・では、ありません。ハードもソフトもまだまだ一般化する段階ではない操作難易度です。(私が持っているプリンターは少々古いので、今はもっと簡単かもしれません。)

基礎知識と最低限の技術がないと、ぐちゃぐちゃの失敗作しか出力できません。

そして、私の手元には、たくさんのぐちゃぐちゃが出来上がりました。

・・・なんだか、失敗する環境設備を作るために、失敗を繰り返している状態です。

印刷できるまでの長い道のり

ハマるところはいくつもありましたが、第1層目の印刷は、有名なハマりどころだと思います。

フィラメントが土台に定着せず、ぐちゃぐちゃになります。

マスキングテープを敷いた上に、のりを付けすると・・・

これで、だいたい定着しています。

第1層目が定着しないのは対応策の情報も見つかりやすく、しっかり情報収集ができていれば、ハマりどころではなかったかもしれません・・・。

なお、この写真は、BONSAI社の3Dプリンター「BS01+」で、テスト用に人型のモデリングデータを印刷しているところです。

印刷後の仕上げ

熱でフィラメントを溶かして積み上げていく印刷方式の場合、安定して積層できるように、バリみたいなものが付いた状態で印刷されます。

それを、ペンチで切り離していきます。

できました。想像したよりきれいです。

「BS01+」は印刷精度は優秀だと思います。

なお、表から見るときれいですが・・・

裏がガサガサ。

やすり掛けか、第1層目の印刷をもっときれいにするか・・・どう対処すれば?

 

まだまだ失敗の積み重ねが必要になりそうです。

電子工作をちょっとだけ面白く

電子工作の「Hello World」・・・Lチカ。

LEDを光らせる機会は多いので、少々味付けをしましょう。

「おゆまる」を入手

お湯で柔らかくなる粘土みたいな「おゆまる」を、ホームセンターで購入しました。

70度くらいのお湯に入れ、柔らかくなったら造形し、冷えると固まります。

ベロを出す得体のしれない生き物

赤いLEDを緑のおゆまるで包みました。(写真左)LEDの足をL時に曲げ、下腹部から出しているので、ブレッドボードに挿せます。

目玉を取り付け、ベロを出すカエル?ぽいものができました。

ついでに、ジャンパーワイヤーの片側を、紫のおゆまるで包んで作ったオタマジャクシもあります。(写真右)

このオタマジャクシ、もし、おゆまるに微弱な電気が流れるなら、タッチセンサーとして使えるかもしれません。

おゆまるはタッチセンサーにはならない

タッチセンサーになるわけが、ありませんでした。

静電容量方式のタッチセンサーとしては機能しません。微弱な電気も流しません。

みずみずしい見た目で、いけるかもと思った私が愚かでした。

ベロ型LED 点灯実験

オタマジャクシのしっぽから、導線を出しました。

ここはタッチセンサーとして機能するので、昨日の回路とプログラムを使い、LEDの点灯実験です。

カエルっぽい生き物のベロが光ります。

子供には好評でした。

 

電気工作を子供と楽しむとき、ちょっと「おゆまる」で手を加えると、楽しくなります。

タッチセンサーの仕組みを子供と勉強

第19回 IoT×プログラミング教育

スマホの普及で一気に身近になったタッチセンサー。
その仕組みを子供といっしょに勉強したいと思います。

ESP32でタッチセンサー実験

タッチセンサーの認識方式はいくつかあるようですが、今回はお手軽に実験できる、ESP32のタッチセンサー「静電容量方式」について学びます。

静電容量方式とは?

「静電容量方式」・・・文字から察するに、静電気を帯びている量によって、タッチしたか判断する方式のようです。

金属ほどではないですが、人にも電気が流れます。

電気が流れるということは、静電気(静止した電気)じゃなくなるので、静電気の容量が減ります。それを感知してタッチしたと判断する仕組みなのでしょう。

検証に回路不要

ESP32開発者ボードをPCに繋ぎ、ESP32のサンプルスケッチ「TouchRead 」を書き込むだけで検証できます。

IO4(T0)ピンを触れば、シリアルモニタの値が下がります。

通常は50くらい、触ると10くらいまで下がります。

50あった静電気が、10しかなくなりました。40は体の中に流れています。(感覚的にそんなイメージ?)

タッチしたらLEDが光るように

見た目でタッチの反応が分かるよう、タッチしたらLEDが光る回路を作ります。

IO23ピンにLEDをつなぎました。

また、触りやすいように、IO4(T0)ピンをジャンパーワイヤーで延しています。

プログラムは以下です。

#define TOUCH_PIN T0 //タッチ入力 4番ピン
#define LED_PIN 23
int val;

void setup(){
  Serial.begin(115200);
  pinMode(LED_PIN,OUTPUT);
}
 
void loop(){
  val = touchRead(TOUCH_PIN);
  Serial.println(val);
  if(val < 25){
    digitalWrite(LED_PIN,HIGH);
  }else{
    digitalWrite(LED_PIN,LOW);
  }
  delay(100);
}

静電気の値は25を基準にして、タッチしたか判断します。

時々、値が安定せず、タッチしなくても光ることがあります。
・・・まあ、現段階では見逃しましょう。

これで、準備が整いました。

子供に伝えられるか?

ピンにタッチしたら、LEDが光る仕組みを例として、ここからは6歳の長男に、図解を交えて説明します。

多少強引な説明もあるかもしれませんが、マイコンのこと、静電気のこと、人に微弱な電気が流れることを、楽しく理解してもらえれば良いです。

ちなみに冒頭の絵を見せたら、マネしておなかにピンを挿すようになってしまいました・・・。

静電気がピンに溜まる

まず、マイコン(EPS32)は、電池をつなぐと、ピンに静電気を溜めます。

静電気は、動いていない電気のことですが、本当は動きたくてうずうずしています。

静電気は触れると移動する

静電気が溜まったピンに人が触れると・・・電気が人に移動します。

とても弱い電気なので、バチッとはなりません。大丈夫です。

この時、マイコンは電気が動いたことに気が付きます。

電気が動いたら何をする?

マイコンにプログラムを書いておけば、静電気が動いたとき、何かをさせることができます。

今回は、静電気が動いたとき・・・つまり、タッチしたときに、電球を光らせるプログラム(命令)を書き込んでいます。

プログラムを変えれば、他のこともできます。

例えばタッチしたら開くドアとか、タッチしたら音が鳴る楽器とか・・・アイデアと部品があれば、いろいろなことができます。

 

以上。

しきりに、「マイコンはしゃべらないよ。」と、子供に言われましたが、静電容量方式タッチセンサーの仕組みは、理解しているようです。

電気を自分の中に流すことを、楽しんでいました。

ボッチャ ソナー2号

ボッチャソナー2号を開発中です。

レクリエーションボッチャを楽しくすることが目標です。

レクリエーション用のタマゴ

レクリエーションボッチャで、ペットボトルにボールを近づける練習(遊び)をすることがありますが、何か物足りない・・・。

そこで、ペットボトルの代わりにタマゴ型ソナーを置こうと思います。白いタマゴはジャックボールみたいで違和感がありません。(たぶん)

アプローチと壁の練習

このタマゴ型のボッチャソナー2号は、1号と比べ、精度と計測速度が上がっています。その代り360度計測できなくなりました。
思い切って、前方90度しか測れなくしています。

角度を絞った理由はいくつかありますが、ボッチャの基本練習を想定していることが、理由の1つです。

ボッチャの基本は「アプローチ」と呼ばれるジャックボールに寄せる投球です。寄せる際、ジャックボールの手前でボールを止め、相手の投球進路を妨害する「壁」をつくる戦術が一般的です。

このタマゴが、「アプローチ」と「壁」の練習になればと考えています。

タマゴの中身は?

タマゴの中身をさらします。

ぐちゃぐちゃの機械ですが、タマゴの中に収めるよう改修します。そして恐竜の被り物を着せて、かわいくする予定です。

リアルタイム描画ソナー

パソコンとつなぐとソナーが描画されます。物体が近いほど、明るい緑のラインが引かれます。

ちなみに上の写真では、中央から右にかけて、カメラを撮影する私が感知されています。

開発に少々苦戦していますが・・・タマゴが「5.3センチだよ」と合成音声で距離をしゃべる予定なので、パソコンなしでも楽しめます。

ボッチャソナーの実動

ボッチャソナー(タマゴなし)の実動画像です。

もう少し画質がきれいな動画も掲載。

距離データ取得しながらレクリエーションボッチャのゲーム性を強め、楽しく達成感を感じられる仕組みを作ることを目指します。