PCのカメラで顔検出するまで

毎年の授業のネタとしてOpenCVで顔検出(face detection)をさせているが、せっかくなのでROS経由で顔検出させることにした。

カメラの設定

まずは、ノートPCについているカメラを使えるようにする。参考にしたのはこちらのサイト。
ロボット作成日記「カメラ画像の表示 」
カメラによって使えるカメラドライバは変わるが、うちの環境ではros-groovy-camera-umdを導入するだけでよかった。この導入により、uvc_cameraのパッケージが利用可能となる。
sudo apt-get install ros-groovy-camera-umd

ちゃんと動作するかどうか、以下を起動して確認する。
rosrun uvc_camera camera_node
rosrun image_view image_view image:=/image_raw

前者でカメラノードを立ち上げ、後者でカメラ画像を表示している。なお、カメラからの画像は/image_rawトピックを通じて得ることができる。

OpenCVパッケージの導入

顔検出に必要なOpenCVのパッケージとして、 ros-groovy-mjpeg-server をインストールしておく。
sudo apt-get install ros-groovy-mjpeg-server

顔検出

顔検出には、OpenCVのHaar分類器を用いたpi_face_trackerというノードを使うことにする。他にもface_detectorがあるがステレオ画像を対象としているようなのでpi_face_trackerにした。ただし、ubuntuのパッケージにはなっていないのでビルドする必要がある。
説明の都合上、~/workspaceでROSのワークスペースが作られているものとする。
先ほどのページの指示に従い、SVNから最新のpi_visionのソースを取り込んでビルドする。
cd ~/workspace/
svn co http://pi-robot-ros-pkg.googlecode.com/svn/trunk/pi_vision
rosws set ~/workspace/pi_vision/
. ~/setup.sh
rosdep install pi_vision

rosdep installでは以下のようなエラーが表示されてしまう。
ERROR: the following packages/stacks could not have their rosdep keys resolved
to system dependencies:
pi_face_tracker_gui: Missing resource rosbridge
ROS path [0]=/opt/ros/groovy/share/ros
ROS path [1]=/home/itoh/workspace/pi_vision
ROS path [2]=/opt/ros/groovy/share
ROS path [3]=/opt/ros/groovy/stacks
ros2opencv: Missing resource uvc_cam
ROS path [0]=/opt/ros/groovy/share/ros
ROS path [1]=/home/itoh/workspace/pi_vision
ROS path [2]=/opt/ros/groovy/share
ROS path [3]=/opt/ros/groovy/stacks
pi_face_tracker: Missing resource uvc_cam
ROS path [0]=/opt/ros/groovy/share/ros
ROS path [1]=/home/itoh/workspace/pi_vision
ROS path [2]=/opt/ros/groovy/share
ROS path [3]=/opt/ros/groovy/stacks

pi_visionの使っているノードが見つからないというエラーなので、rosbridgeをrosbridge_server、uvc_camをuvc_cameraのように修正していく。
rosbridgeに関する修正は、pi_vision/pi_face_tracker_gui/manifest.xml に対して行う。下から4行目あたりのrosbridgeをrosbridge_serverに変更する。変更した後の内容は以下の通り。
<depend package="rosbridge_server"/>
uvc_camに関する修正は、pi_vision/ros2opencv/manifest.xmlとpi_vision/pi_face_tracker/manifest.xmlの2カ所に対して行う。どちらも、uvc_camをuvc_cameraに変更する。
<depend package="uvc_camera"/>
続いてrosmakeする。
rosmake pi_vision
この状態で起動することはできるのだが、uvc_cameraの画像トピック名が/image_rawであるのに対して、pi_face_trackerでは/camera/image_rawを使っている。そのため起動しても画面には何も表示されない。pi_vision/pi_face_tracker/launch/face_tracker_uvc_cam.launch の5行目にある/camera/image_rawを/image_rawに変更する。変更した後の内容は以下の通り。
<remap from="input_rgb_image" to="/image_raw" />
以上でビルドは完了。

使い方

roslaunch ros2opencv uvc_cam.launch
roslaunch pi_face_tracker face_tracker_uvc_cam.launch

uvc_cameraノードを起動しておき、face_trackerを起動する。
自動的にimage_viewが立ち上がり検出後の画像が表示される。
画面上でのショートカットキーは以下の通り。

  • q – 終了
  • c – 現在の特徴を削除する
  • t – テキスト表示のオン/オフ
  • f – 特徴表示のオン/オフ
  • n – ナイトモード(カメラ画像表示しない)のオン/オフ
  • a – 自動的な顔検出のオン/オフ

Pharo 2.0 でのサウンド

goonshさんのKhorosの正式リリースを心待ちにしているのだが、学生から音ゲーを作りたいとの要望がでて、Pharo 2.0で音関係がどうなっているのかを調べてみた。
Pharoの本体からは外されてしまっているが、外部パッケージとして昔と同じ(?)ものを使うことができる。

MCHttpRepository
	location: 'http://www.smalltalkhub.com/mc/PharoExtras/Sound/main'
	user: ''
	password: ''

上記をMonticelloで+RepositoryしてOpenし、ConfigurationOfPharoSoundを選んで最新版をロードする。
Workspaceを開いて以下をDo itすればOK。
ConfigurationOfPharoSound project load: #stable
動作確認は以下のようにする。
AbstractSoundSystem soundEnabled: true.
AbstractSound stereoBachFugue play.

バッハのフーガが演奏されればOK。止めたくなったら以下をDo itする。
SoundPlayer stopPlayingAll.
ちなみに上記はMac OS X 10.8.3(Mountain Lion)で確認した。Windows 7で同じように動くかどうかは要チェック。

ScorePlayerMorphへのパッチ

(2013.5.30追記)
Mac OS X, Windows 7ともに適切なMIDIポートを選べばMIDIファイルを演奏できる。ただし、MIDIファイルを選択する際にエラーが出るため、一部修正する必要がある。なお、以下を保存してFileInすれば対処できる。
ScorePlayerMorph-openMIDIFile.st

OpenJTalkの導入

TurtleBot1に喋らせるためにOpenJTalkを導入した。OpenJTalkとは、日本語で書かれた文書を読み上げるオープンソースのソフトウェアである。
http://open-jtalk.sourceforge.net/
例によってubuntu(12.04LTS)のレポジトリから入手できるバージョンは古いため、上記サイトから最新版を導入することにした。
導入の方法はOpenJTalkを使ってみる。が詳しい。ほぼ同じ手順でインストールした。

準備

http://open-jtalk.sourceforge.net/より、以下のファイルをダウンロードする。

  • open_jtalk-1.06.tar.gz
  • open_jtalk_dic_utf_8-1.06.tar.gz
  • hts_voice_nitech_jp_atr503_m001-1.05.tar.gz

また、http://hts-engine.sourceforge.net/より、以下のファイルをダウンロードする。

  • hts_engine_API-1.07.tar.gz

上記を適当なフォルダに保存しておく。ここでは説明の都合上、~/Downloads に保存したものとする。

ビルド

手順としては、

  1. hts_engine_APIのビルド
  2. open_jtalk-1.06にパッチを当てる
  3. open_jtalk-1.06のビルド

の順でビルドを行う。
例によって ~/workspace フォルダに上記ファイルを展開していくものとする。

hts_engine_APIのビルド

cd ~/workspace
tar xzf ../Downloads/hts_engine_API-1.07.tar.gz
cd hts_engine_API-1.07
./configure
make
sudo make install

open_jtalk-1.06にパッチを当てる

何もせずにopen_jtalkをビルドすると、文章によっては読み上げの途中でものすごく間延びすることがある。これを解決するにはソースにパッチをあてる必要がある。

*** jpcommon/jpcommon_label.c.orig      2012-12-24 17:18:53.000000000 +0900
--- jpcommon/jpcommon_label.c   2013-05-27 16:35:45.195252424 +0900
***************
*** 284,289 ****
--- 284,290 ----
        if (index == a)
           break;
     }
+    if (i > 3) i = 3;
     return i;
  }
***************
*** 383,388 ****
--- 384,390 ----
     for (i = 0, index = m->next; index != NULL; index = index->next)
        i++;
+    if (i > 10) i = 10;
     return index_mora_in_utterance(m) + i;
  }

上記を適当なファイルmanobi.patchにコピー&ペーストしてworkspaceフォルダに保存する。その後以下を実行する。
cd ~/workspace
tar xzf ../Downloads/open_jtalk-1.06.tar.gz
cd open_jtalk-1.06/
patch -p0 < ../manobi.path

open_jtalk-1.06をビルドする

パッチが成功したら続けてビルドする。
./configure --with-charset=UTF-8
make
sudo make install

各種データファイルの設定

辞書ファイルおよび音声ファイルを展開する。
tar xzf ../Downloads/hts_voice_nitech_jp_atr503_m001-1.05.tar.gz
tar xzf ../Downloads/open_jtalk_dic_utf_8-1.06.tar.gz
sudo mkdir /usr/local/share/open_jtalk
sudo mv hts_voice_nitech_jp_atr503_m001-1.05/ open_jtalk_dic_utf_8-1.06/ /usr/local/share/open_jtalk/

実行

open_jtalk -m /usr/local/share/open_jtalk/hts_voice_nitech_jp_atr503_m001-1.05/nitech_jp_atr503_m001.htsvoice -ow output.wav -x /usr/local/share/open_jtalk/open_jtalk_dic_utf_8-1.06/
上記を実行すると入力待ちになるので、適当な日本語文章を入力してEnterを押す。すると、その文章を読み上げたファイル(output.wav)が生成されるため、適当なプレイヤー(mplayer等)で再生すればよい。
パラメータが長いので適当なシェルスクリプトを作っておいた方がいいだろう。

Juliusの導入

TurtleBot1で音声認識をさせるべく、Juliusをインストールしてみた。
大語彙連続音声認識エンジン Juliusによると、Juliusは以下のような音声認識エンジンである。

Julius は,音声認識システムの開発・研究のためのオープンソースの高性能な汎用大語彙連続音声認識エンジンです. 数万語彙の連続音声認識を一般のPC上でほぼ実時間で実行できます. また,高い汎用性を持ち,発音辞書や言語モデル・音響モデルなどの音声認識の各モジュールを組み替えることで,様々な幅広い用途に応用できます. Julius はオープンソースソフトウェアで,ソースコードを含めてどなたでもフリーで入手することができます.

ubuntu(12.04LTS)のレポジトリのものは4.1.5と古かったので、最新のソースからビルドすることにした。

準備

Juliusのサイトから以下のファイルをダウンロードする。

  • julius-4.2.2.tar.gz
  • dictation-kit-v4.1.tar.gz

dictation-kit-v4.1(Juliusディクテーション実行キット)にはJulius本体が同梱されているが、バージョンが古いため最新のエンジンを用意しておく。
なお、説明の都合上、~/Downloadsに保存したものとする。

ビルド

上記のファイルを適当なフォルダ(ここでは~/workspaceとする)で展開する。
cd ~/workspace
tar xzf ../Downloads/julius-4.2.2.tar.gz
tar xzf ../Downloads/dictation-kit-v4.1.tar.gz

julius本体をビルド&インストールする。
cd julius-4.2.2
./configure
make
sudo make install

実行

以下のコマンドでJuliusを起動すると、連続的に音声認識を行い、認識結果がUTF-8で表示される。
julius -C ~/workspace/dictation-kit-v4.1/fast.jconf -charconv EUC-JP UTF-8

moduleモード

以下のコマンドではmoduleモードで起動する。
julius -C ~/workspace/dictation-kit-v4.1/fast.jconf -module -charconv EUC-JP UTF-8
moduleモードにするとJuliusはポート10500番でlistenし、TCPで接続してきたクライアントに認識結果がXML形式で送られる。
なお、JuliusBookには連続的な接続・切断をサポートするようなことが書かれているが、実際には切断するたびにJuliusが終了するので注意。

注意点

マイクの種類や音量には敏感なようなので微調整が必須。ディクテーションキットの辞書ではそれほど認識精度も高くない。ちゃんと認識させるにはそれなりの学習が必要と思われる。

ROS経由でKinectの骨格情報を得る(groovy)

以前、ROSでkinectを動かす。という記事で、Kinectの骨格情報をROS経由で得る方法について述べた。しかし、相当に古い情報なので、現在のgroovyではうまく動かないようだ。
そこで、groovyで動かす方法を再度まとめてみた。
2013/10/3追記:この件に関してまとまっているサイトを見つけたので追加しておく。
http://www.technolabsz.com/2013/06/how-to-solve-opennitracker-error-find.html
基本的には、openni_trackerというパッケージを導入することで骨格情報が扱えるようになるらしい。
sudo apt-get install ros-groovy-openni-tracker
上記のようにインストールし、
roslaunch turtlebot_bringup 3dsensor.launch
でKinectを動作させた後で、先ほどのページに記述されているようにtrakerを起動した。すると、
rosrun openni_tracker openni_tracker
[ERROR]: Find user generator failed: This operation is invalid!

のようなつれないメッセージとともに終了してしまう。
適当にググって探してみると同じ現象についての報告がされていた。
OpenNI/NITE incompatible in Fuerte/Groovy on Precise
要はNITEのバージョンが異なるためらしいのだが、5番目のコメントの方法を試してみたらうまくいった。
まず、OpenNI SDK historyのページから、NiTE v1.5.2.21のパッケージをダウンロードする。(うちの32bit版ubuntu12.04の場合、NITE-Bin-Linux-x86-v1.5.2.21.tar.zipとなる。)
ダウンロードしたZIPファイルを展開すると、bz2形式の圧縮ファイルが得られるので、さらにtar xjfコマンドで展開する。展開したフォルダの中にinstall.shというスクリプトがあるので、以下のようにインストールする。
sudo ./install.sh
これで先ほどのrosrun openni_tracker openni_trackerを実行するとエラーを吐かなくなった。
しかし、Kinectの前でPSIポーズを取ってみてもウンともスンとも言わない。アヤしいと思って、roslaunch turtlebot_bringup 3dsensor.launchを止めて別のlaunchを試したらうまくいった。
roslaunch openni_launch openni.launch
まとめると、以下の手順でKinectが骨格情報を生成するようになった。

  1. ros-groovy-openni-trackerをapt経由で得る
  2. NiTE v1.5.2.21をダウンロードする
  3. roscoreなりturtlebot_bringupしておく
  4. roslaunch openni_launch openni.launchを起動する
  5. rosrun openni_tracker openni_trackerを起動する

上記のパッケージは骨格情報を認識すると、/tfトピックにデータを流すようになる。そこで、/tfをsubscribeして適当にデータを得ればいいのだが、気をつけなければならないのは、child_frame_idに現れるのは、trackerのページにあるような/headではなく、認識したUserの番号が付加された/head_4のようなものとなることである。後は0〜1の範囲にあるx, y, zから値を得れば良い(はず。まだやってない。)

VirtualBox(Host OS=Mountain Lion, Guest OS=Ubuntu 12.04)上でArduino UNOと通信する方法

長ったらしいタイトルだが、すっかりハマってしまったのと、かなり特殊な事例のようなので書き残しておく。
まず、目的を述べておくと、MacBookAir上のMountain Lionで動作させたVirtualBox上のUbuntu 12.04LTSで、Arduino UNOのプログラムを開発できるようにすること。なんでこんなことをしたいかというと、Ubuntu上でROSを動かしており、rosserialでArduinoと通信させたいからである。
当初は簡単に思えたが、結構ハマって時間がかかってしまった。
最初に思いついたのは、VirtualBoxの方でUSBコントローラを生かしておき、ArduinoのUSBデバイスをUbuntu側で認識させるというもの。このやり方だと認識はうまくいきUbuntu側のArduino IDEでコンパイルまではうまくいくものの、プログラムを転送する段になってエラーで止まってしまう。
ググってみても解決方法は見当たらないので、別の方法を試すことにした。
次の案は、VirtualBoxの仮想シリアルポートの機能を使うこと。VirtualBox VMの設定を見回したところ、シリアルポートを有効化して「ホストデバイス」なる指定を行うとうまくいきそうな感じである。実際、Host=Windowsであればうまくいく例もあるようだ。
Macの場合、シリアルポートのポート1を有効化してポートモードをホストデバイスに切り替え、ポート/ファイルパスを「/dev/cu.usbmodem621」に設定したところ、みごとUbuntuで/dev/ttyS0として認識され、問題なくプログラムが転送されるようになった。
ハマったのは最初はMac上のArduino IDEで認識される「/dev/tty.usbmodem621」を設定したところ、VirtualBox VMが起動せずにフリーズする現象にあったことだ。まだcuとttyの違いがよくわからない。
なお、621という数値部分は環境によって変わるかもしれない。うまくいかなければターミナル等で「ls /dev/cu.*」を実行して似たようなのを探すべきだろう。
とりあえずすっきりした。rosserialについては別記事にまとめる予定。

MacでArduinoを使う(2)

久しぶりにMacでArduinoを使うべく、ソフトウェアのインストールを行った。

ダウンロードとインストール

Arduinoのサイトで、Downloadの欄のMac OS Xをクリックし、zipファイル(現時点では、arduino-1.0.4-macosx.zip)をダウンロードする。
次にzipファイルをダブルクリックして解凍し、生成されたArduinoというファイルをアプリケーションにコピーする。
アプリケーションフォルダのArduinoファイルをダブルクリックして起動すると、すぐには起動せずにアップデートの確認ダイアログが現れて、Java for Mac OS Xがインストールされた。確認ダイアログをOKした後でArduinoが起動した。

Arduinoの接続

起動したArduinoを終了させ、USBケーブルでArduinoとMacを接続する。本来だとここでネットワーク接続のダイアログが出るはずだが、何もでない。ネットワーク環境設定の画面を開くと、既にArduino Unoのエントリが作成されていた。多分、以前に導入したときのものがTimeMachineのバックアップに残っていたのだろう。
スクリーンショット 2013-04-06 22.47.37
Arduinoを起動するとArduino Uno on COM1と表示されている。ファイルメニューから、スケッチの例 – 01.Basics – Blinkを選んでサンプルのスケッチを開き、上段にある右向きの矢印(マイコンボードに書き込む)をクリックすると、COM1が見つからないとのエラーメッセージとともにデバイス選択のダイアログが現れた。
スクリーンショット 2013-04-06 22.46.01
(画面はエラーを再現すべくケーブルを抜いた後で転送させたときのもの)
どれが正しいのかわからなかったが、勘で /dev/tty.usbmodem411 を選んだら接続されてスケッチが転送され、Arduino上でプログラムが動き出してオレンジ色のLEDが点滅を繰り返し始めた。

rosbridge経由でPharo 2.0からROSに接続する

PharoからROSに接続するのに、以前はrospharoというパッケージを作っていたが、古いバージョン用(diamondback)でありアップデートも面倒臭いので、今回はrosbridgeを用いて接続することにした。rosbridge V2.0ではWebSocketを用いて接続するので、Pharo 2.0から接続するには両者のインストールが必要となる。
rosbridgeとWebSocketのセットアップは以下にある。

rosbridgeのサイトではChromiumブラウザのWebSocket接続機能を使って動作確認を行っているが、やはりPharoerとしてはPharoから動作確認したい。そこで、まずROS側で適当なTopicをPublishしておいて、それをPharo側でSubscribeして動作確認することにした。以下、ROS側とPharo側で分けて説明する。

ROS側の作業

前述のrosbridgeの導入の通り、roscoreおよびrosbridgeを起動しておく。
turtle_teleop_keyは、タートルグラフィックスシミュレータのタートルをカーソルキーで操作するためのNodeである。手近なところでPublishできるノードを思いつかなかったので、これを使うことにした。
別のターミナルなどを用いてturtle_teleop_keyを起動する。
rosrun turtlesim turle_teleop_key
更に別のターミナルなどで以下を入力する。
$ rostopic list
/rosout
/rosout_agg
/turtle1/command_velocity

/turtle1/command_velocityというトピックが現れているのがわかる。以下を入力してどんなメッセージかを調べる。
$ rostopic type /turtle1/command_velocity
turtlesim/Velocity

/turtle1/command_velocityトピックではturtlesim/Velocityというメッセージが使われている。より詳細に調べるには以下のようにする。
$ rosmsg show turtlesim/Velocity
float32 linear
float32 angular

turtlesim/Velocityメッセージは、2個のfloat32型変数linear, angularで構成されていることがわかる。
ちゃんとturtlesim/Velocityメッセージが来るかどうかチェックする。
$ rostopic echo /turtle1/command_velocity
ここで、turle_teleop_keyを起動したターミナルでカーソルキーを入力する。上下左右のカーソルキーを順に入力すると、ターミナルに以下のように表示される。
$ rostopic echo /turtle1/command_velocity
linear: 2.0
angular: 0.0
---
linear: -2.0
angular: 0.0
---
linear: 0.0
angular: 2.0
---
linear: 0.0
angular: -2.0
---

Pharo側の作業

WebSocketをインストールしたPharoを起動し、適当なワークスペースを開き、以下を入力する。なお、以下の説明ではrosbridgeの動いているPCのIPアドレスを192.168.254.68としている。
rs := ZnWebSocket to: 'ws://192.168.254.68:9090'.
rs sendMessage: '{"op": "subscribe", "topic": "\/turtle1\/command_velocity", "type": "turtlesim\/Velocity"}'.

1行目でrosbridgeへWebSocket経由で接続している。2行目では/turtle1/command_velocityトピックをSubscribeしている。このときメッセージタイプも指定している。なお、rosbridgeとのやりとりにはJSON形式のデータを送る。
上記をDo itすると、rosbridgeのターミナルに以下のようなログが出力される。
[INFO] [WallTime: 1363827799.919737] [Client 0] Subscribed to /turtle1/command_velocity
続いてワークスペースで以下を入力してPrint itする。
rs readMessage.
タイムアウトになる前にturle_teleop_keyのターミナルに戻って、上カーソルキーを押すとPrint itの結果が表示される。
'{"topic":"\/turtle1\/command_velocity","msg":{"linear":2.0,"angular":0.0},"op":"publish"}'
opコードにpublishが、msgにlinearとangularの値が入ったJSON形式のデータが返ってくる。
トピックのsubscribeをやめ、rosbridgeとの接続を解除するには以下のようにする。
rs sendMessage: '{"op": "unsubscribe", "topic": "\/turtle1\/command_velocity"}'.
rs close.

ちゃんとrosbridge経由で通信できることが確認できた。

Pharo 2.0にWebSocketをインストールする

rosbridgeとの接続にはWebSocketを用いるのでWebSocketをPharoにインストールする。
WebSocketはZincのパッケージにあるが、Pharo 2.0のデフォルトの配布パッケージには入っていないので別途インストールする。
Monticelloを起動して+RepositoryでHTTPを選び、以下を入力する。
MCHttpRepository
location: 'http://www.squeaksource.com/ZincHTTPComponents'
user: ''
password: ''

Openでリポジトリを開き、左側のペインからZinc-WebSocket-CoreとZinc-WebSocket-Testsを選んで最新版をLoadする。
とりあえずテストして動作確認する。
(proxy環境だと一部のテストに失敗するが気にしない)

rosbridge V2.0の導入

ROSにrosbridgeを導入する。最近はV2.0に移行しており以前のものとはプロトコルが異なるとともに、WebSocketに対応している。
2013-5-10追記
rosbridge v2.0はROSの正式なパッケージとなったようだ。
http://ros.org/wiki/rosbridge_suite
導入手順は簡単で、以下だけでOK。
sudo apt-get install ros-groovy-rosbridge-server
rosbridgeサーバーの起動は少し変わって以下のようになった。
roslaunch rosbridge_server rosbridge_websocket.launch
以下の情報は古い
ROS/groovyをインストールしたマシン上にrosbridgeをインストールする。手順は以下のサイトを参考にした。
downloading_rosbridge
あらかじめrosパッケージ用のディレクトリを作成し、パッケージのPATHも通しておく。
mkdir ~/ros
export ROS_PACKAGE_PATH=~/ros:$ROS_PACKAGE_PATH

gitで最新のソースツリーを取り込む。
git clone http://kforge.ros.org/rosbridge/git rosbridge
makeする。
rosmake rosbridge
以上でrosbridgeのパッケージが作成される。
動作確認のためにrosbridgeサーバーを起動する。
roscore &
rosrun rosbridge_server rosbridge.py

起動すると以下のようなメッセージが表示される。
[INFO] [WallTime: 1363825226.008247] Rosbridge server started on port 9090
続いてクライアント側を整備して接続を行ってみる。