OpenCVをつかってRTCを作成するときの俺ルール

もうすぐOpenRTM-aist 1.0 RC1がリリースされるみたいですね。私は福岡には行けませんが、早めに試したいですねー。

USBカメラドライバが安定しているWindowsから親離れできない私はいつもVC++コンポーネントを実装してRTCLinkやRTSystemEditorを用いて実行(デバッグ?)しています。RTSystemEditorを使っているとコンフィグレーションで変数をチョコチョコ変えられるのが便利です。今日はOpenCVを用いたRTCを作り散らかしている私の小知恵をメモしておきます。
※ これがベストだなんてこれっぽっちも思っていません。デバッグの方法は十人十色です。rtcHandleをつくった電通大末廣氏のようにコンソール好きの人はこれ読んでもあまり収穫はないかもしれないです。

画像データ用のInPort/OutPortにはTimedOctetSeq型を用いる

これはたぶん皆さんこうしていると思います。ただそれはdepthが8bitだから成立している暗黙のルールで、depthのビット数が増えたらまた考える必要があります。 私的には最初の数バイトにヘッダ的な情報(channel, sizeなど)を格納できればいいなと思いますが、これは統一ルールを定めないといけないんでしょうね。

コンフィグレーションから画像サイズを設定する

まぁ、これも阪大田窪氏のコンポーネント群を見た方であれば誰でも真似をします。コンポーネント内で持つ画像バッファはonActivated()でインスタンス化(cvCreateImage()など)すればいいので、そのときにコンフィグレーションの値を引数に設定します。
ご存知の方も多いかと思いますが、cvSetCaptureProperty()はWindows上ではほとんど言うことを聞いてくれません。(誰か理由や対策をご存知の方はご教授ください) LogitechPhilipsのカメラデバイスは、そのデフォルトの画像サイズが決まっているようです。私の場合、QCam E3500ではQVGAなのにQCam Pro9000だとVGAになります。原因を把握していないとQVGAのバッファにVGAの画像サイズをmemcpyしようとしてコンポーネントごと落ちます。だからといっていちいちサイズを変更してコンパイルするのは面倒です。なのでDeactivateしてコンフィグレーションを変更すればいいというわけです。できればonExecute()のたびに入ってきたデータポートのサイズを判断して動的にバッファを確保できるようにしたいので、期限は決めていませんが、がんばります。

コンフィグレーションでウィンドウ表示の可否を設定する

上記の同様にcvNamedWindow()はonActivated()で実行するものなので、コンフィグレーションの値で分岐処理すればウィンドウ表示を制御できます。阪大田窪氏のコンポーネントは最後に"ゴール"として繋げるだけのウィンドウ表示専用RTCを用意して、途中経過を確認することができません。かといってすべてのRTCがウィンドウ表示してたらウザいことになります。リアルタイム性や速度を求めるならウィンドウ表示せずに描画時間を節約すればいいし、状況をみたいときだけそのRTCのコンフィグレーションをいじくれば処理結果が見られる、というふうにできればベターかなと。

読み込むファイル名はテキストに書いておく

これはOpenRTMの不便なところを補うためにやっています。cvLoadImage()とかで画像ファイルを読み込む必要があるとき、皆さんはどうしますか?できればコンフィグレーションでファイル名を書いたらそのファイルを読み込んでくれるのがベストなのですが、残念ながらコンフィグレーションで文字列が入力できません。なので私はテキストファイルにファイル名を書いて、そのファイルをfopen()しています。ファイル名を直すよりちょっと楽です。
私が勉強不足なだけかもしれないので、やり方をご存知の方がいたらご教授ねがいます。

カウンターを張ってパフォーマンスを監視

これは本当に私だけのルールなので気にしないでほしいのですが、画像処理やっているとフレーム数が気になります(私だけ?) 基本的にコンポーネントの粒度を小さくすると画像をキャプチャするコンポーネントだけやたら遅くなって他のコンポーネントのonExecute()は高速でループして、RTC間で処理速度に落差ができてしまいます。ミドルウェア設計者の方々から言わせれば、それが正しいのかもしれませんが、やはり気になってしまうのでonExecute()のたびにインクリメントするカウンターを作っています。cvPutText()などで画面に表示すればウィンドウ上で処理速度が監視できます。またメモリリークなどでフレームが前後することもあるので気になるところには結構つかいます。

cvShowImage()のあとにcvWaitKey()

これは別にルールというよりそうしないと困るのですが、cvShowImage()のあとにcvWaitKey()を入れないとウィンドウに画像が表示されません。私だけでしょうか。まぁ引数はいくつでもいいのですが、とにかく入れてます。
あとOpenCV1.1についてくるvideoInputライブラリも使えません。実行してもActivateできませんでした。原因をご存知の方ご教授ねがいます。願いばかりですいません。

カメラ情報を他のRTCから参照できるようにする

素数もそうですが、カメラの視野角の情報も座標変換しようと思ったら重要だと個人的に考えています。私は三角関数で相対角度やカメラ座標を求めようとしているので、例えば相対距離(奥行き:Z軸?)が既知であれば視野角と画面上のXY座標から相対角度が求まるのでカメラ座標も求めることができます。この考え方は素人考えの発想なので学者や理系の学生さんからお叱りを受けるかもしれませんが、大体の範囲で実世界に適用できるし、実装も簡単なので"自己流の馬鹿"だと思ってお許し頂きたく。
で、画像キャプチャコンポーネントにサービスポートかなんかで情報取得のインターフェースがあるといいなと考えています。まだ実装していないので、ルールではなく目論見です。

コメントを入れる

ロボットをやっていると物理学や数学の難しい式や演算をコードに落とすことがあります。たとえば私が今やっているハンドアイなどはカメラ座標からロボット座標に変換する処理が必要です。回転行列と並進成分を算出するために行列の知識が必須となります。画像解析では、エッジの勾配・方向を算出するためにベクトル、ヒストグラムや特徴量抽出で微分が超重要です。
歴史学科出身の私は理系の教養がない人間なので、高校生向けの教科書を読み漁っていますが、一夜漬けなのでなかなか身になりません。せめてコードを書いたらなるべくコメントを入れています。大学の先生などに見られたら笑われるかもしれませんが、私には恥も外聞もないし、社会人になってこの方「コードの可読性が重要だ」と言われて育ったので、ソースに行列式や座標図を書いています。だってその方が後から見て分かりやすいですから。動くものもいいですが、後々に他人が使えるコードも大事ではないかと思うこの頃です。