ロボゼロをコンピュータ制御してみる その6
2012年11月7日


 Androidの顔認識APIを使ってロボゼロを制御してみます。
 サンデーフォトスタジオでOpenCVの顔認識ライブラリィを使っていますが、Androidでは標準でAPIが搭載されているのは驚きです。
 Android版のOpenCV顔認識APIもあるようですが、折角標準であるので今回は標準のものを使いました。
 またロボゼロをリアルタイムで制御するたライブ画像を使って顔認識してみます。
 これまたAndroidではカメラのプレビュー画面を標準のライブラリィを使って取得する事ができます。
 Windowsの場合、これを実現するにはDirectXだのOpenCVだのいろいろかき集めてこないと実現できないのですがAndroidはその点楽ですね。
 詳しい技術解説はネットを探せば詳しく書かれているのでここでは簡単な流れだけ説明します。



 ここで特筆すべき点はカメラプレビュー画面から顔認識に渡す静止画を生成する部分です。
 Camera.PreviewCallbackはカメラプレビューのフレーム毎に呼ばれるコールバックルーチンでここでプレビュー画面を静止画に変換します。
 毎フレーム毎に顔認識をすると処理が追い付かなくなるので間引きをします。
 今回は45フレーム(約2秒)に一度顔認識をするようにしました。

 プレビュー画面は、JpegやBitmapといった標準のフォーマットではなくハードウェアに依存したRAW(生)画像です。
 Androidの顔認識の対象となる画像はJPEG,PNG,BMPといった形式なのでこれらいずれかに変換する必要があります。
 AndroidのクラスにYuvImageというクラスがあります。YUVはRAW画像のイメージを扱うクラスです。
 なおandroid 4.0 からCamera.FaceDetectionListenerというリスナーが追加され、こんな面倒な事をやらなくてもプレビュー画像を直接顔認識する事ができます。

 参考のためこの部分のソースコードを記載しておきます。

 private final Camera.PreviewCallback editPreviewImage =
  new Camera.PreviewCallback() {
  public void onPreviewFrame(byte[] data, Camera camera) {
   if (++mFrameCount > 45) {
    camera.setPreviewCallback(null);
    camera.stopPreview();
    camera.addCallbackBuffer(data);
    YuvImage image = new YuvImage(data, parameters.getPreviewFormat(),
      parameters.getPictureSize().width, parameters.getPictureSize().height, null)
    String path = Environment.getExternalStorageDirectory().getPath() + "/Preview.jpg"
    FileOutputStream fos = null;
    try {
     fos = new FileOutputStream(path);
     fos.write(data);
     image.compressToJpeg(
       new Rect(0, 0, image.getWidth(), image.getHeight()), 40,fos);
     fos.close();
    } catch (IOException e) {
     Log.e("Camera03", e.getMessage());
    }
    顔認識処理に続く

 androidの顔認識にはパラメータで認識する顔の最大数を指定しますが、今回は複数顔が見つかっても処理できないので1にします。

  FaceDetector detector = new FaceDetector(src.getWidth(), src.getHeight(), 1);

 顔認識に成功すると認識できた顔の数が返されます。
 今回は1が成功で0が失敗となり、0の場合はまた次の45フレーム目を顔認識します。



 顔認識が成功した時のプログラムの画面です。(ちなみに私の顔じゃありません)
 認識が成功すると認識結果から認識した目の中心座標と目の間隔が取得できます。
 中心座標から顔の向き、間隔から顔までの距離を推定します。

 ロボゼロにはBluetoothを使って顔の向きと距離を伝えます。
 ロボゼロでは専用のプログラムを走らせておき顔検出のコマンドを待たせておきます。
 顔検出のコマンドはロボゼロBluetoothコントローラーリモコンの前進と同じ2としています。
 コマンドはロボゼロのプログラムV120で送信します。
 それ以外に今回は前進の歩数をV121、向きをV122で送信します。
 歩数はandroidプログラムで顔認識の目の間隔から、向きは目の中心座標から計算します。
 なお今回のプログラムでは音声も使っていますが、従来音声はプログラムと別ファイルでなければいけませんがロボゼロサウンドマージツールを使ってひとつにしています。



 顔認識はandroid携帯がする訳ですがロボゼロが認識しているようにするためandroid携帯をロボゼロに装着してみます。
 携帯をロボゼロに装着するためにシェルカバー(ハードカバー)を使用します。
 どうせ加工するので一番安いのをamazonで探すと何と
1円というのがありました。
 いくら旧モデルの携帯といえどうなっているのでしょうね。
 もちろん別途送料はかかりますが、定型外郵便なので送料込みで171円でした。(到着に時間がかかりましたが)



 ロボゼロの頭を外してそこに携帯のカバーを取り付けます。
 あまり原型をいじりたくなかったのでもともと開いていた穴に2mmのネジで取り付けました。
 さすがに2mmのネジ1本では不安なので両面テープを貼ってからネジどめしてあります。



 携帯を取り付けたところです。  割とカッコ良く仕上がりました。  まさにアンドロイドです。
 1円ケースという事で色とかこだわらなかったのですがミラー仕上げという事でなかなかいい感じです。
 私の携帯は3Dなのでレンズが2個付いています(今回は3Dではありませんが)



 プログラムの実行動画です。
 認識画面は今話題のPSYのGangnam Styleですが、体型が似ているので私の代わりに使っています。

     

 携帯を取り付けたので頭が重くなり標準の前進プログラムだとすぐにコケてしまいます。
 速度を4倍にしたのですがうまく前に進んでくれません。
 今後の改良が必要です。

 androidの顔認識ですが静止画の写真ならかなりの精度で認識してくれます。
 今回はプレビュー画面を使ったのですが、照明をうまく顔に当てると同様に認識してくれます。
 ただし個別の顔の識別はできないので誰でも「ご主人様〜」と反応してしまいます。

目次に戻る