2008年5月アーカイブ

twoViewを使ったプログラム、4つ目はポインティングデバイスです。
これは、前回の3つのプログラムの機能を合わせて作成しています。

------- < 機能の概要 > -------



以下、プログラムの処理です。
1.最初にカメラ間の関係を表す、変換行列を計算しておく
2.次に、特徴的な色の検出を行う
3.2の結果から、その色の物体の位置を検出
4.2つの物体の位置を元に、ポインティングを行う

1~3までは、これまでのtwoViewを用いたプログラムに対応しています。



------- < 4.2つの物体の位置を元に、ポインティングを行う > -------

ポインティングは次のような手順です
1.2つの目印の距離を測る
2.距離が短いときは、クリックしていると判定
3.クリック中に、3Dモデルとの衝突判定を行う
4.衝突していたら、モデルをカーソルと一緒に移動する
5.距離が離れてクリックが解除されたら、モデルの移動も止める



------- < 参考にした作品 > -------




③にも書きましたが、色認識を用いて物体の位置を求めるアイデアは、こちらの動画からいただきました。




求めた物体の座標をポインティングデバイスとして使用するアイデアは、この動画からのものです。


お二人には、この場を借りて感謝いたします。
また、他の開発者の皆さんからも、たくさんアイデアを頂いています。

良い作品を見せていただき、ありがとうございました。
これからも、よろしくお願いします。

長い時間上手くいかず悩んでいましたが、やっとそれらしい結果が出るようになりました。
前回の特徴物体の位置から、物体までの距離を求めます。

featureDist01.jpg   featureDist02.jpg  

featureDist03.jpg   featureDist04.jpg  


参考にしたのは、以下の動画です。



この方は、他にもARToolKitと物理演算を合わせたりと、かなり高度なことをやっています。





今回は、簡単な三角測量を用いて距離計算を行っています。
簡単なケースでは、2つのカメラの向きを平行にして、Y・Z座標の位置も同じにします。

ちなみに失敗していた理由は、VIEW_SCALEFACTORという値を考えていなかったからでした。
これは、ARToolKitの長さの単位から、OpenGLの単位へ変換するときに必要になります。

まだ誤差などがあるようなので、これから調整します。



--------- < 追記 > ---------

○08/05/29

誤差が安定してきたので、処理を大まかに説明。

前回(その②)の各カメラでの、特徴点のスクリーン座標系の位置を取得。
これを、透視投影変換の逆行列を使って、カメラ座標系の位置に変換。

また、その①で求めたカメラ間の変換行列から、カメラのX座標系での距離を取得しておく。

そこで、以下の計算を行う。
1.a = カメラ間のXの距離 / (カメラ1での特徴点のX座標 - カメラ2での特徴点のX座標)
2.カメラ1の特徴点の座標(カメラ座標系)をa倍する。
3.2の結果が、特徴点で示した物体の3次元空間上での座標(カメラ座標系)になる。
4.カメラ1で、マーカーからの変換行列の逆行列を計算しておく
5.2の結果に対し、4の逆行列をかけて、マーカー座標系での特徴物体の座標を計算する。
6.5に対し、VIEW_SCALEFACTORをかけて、OpenGLの長さの単位にする。


このようにして、出た座標を表示すると、最初のような画像になります。
画像では、[マーカー座標系の原点]から[特徴物体の真下]までの線と、そこから[特徴物体]までの線を描画しています。


○08/05/30

まだ微妙な誤差がありましたが、三角測量の倍数の計算で、
X値だけじゃなくY値も入れた距離で計算したら上手くいきました。
日々ARToolKitに関するニュースを探しているPipeRですが、
先日ARToolKitをFlashに移植されたというブログを見つけました。

FlashのActionScriptは昔少しだけ触ったことがありますが、
これでARToolKitを作ってしまえるとは驚きました。



ARToolKitをJAVAに移植したA虎@さんのNyARToolkitといい、
スキルの高い開発者の方々が、ARToolKitのさらなるマルチプラットフォーム化を進めています。

これは、より多くの人がARToolKitを使えるようになる、すばらしいことです。

私の開発の目的はあくまで自分の勉強のためですが、
このような方々のように、もっと有用なプログラムを作りたいですね。



あと有用なプログラムといえば、ギズモード・ジャパンで紹介されていた、
ARToolKitを使ったゲームなんてのもあります。

これも非常に面白くて、ARToolKitを上手く生かしてると思いました。


twoViewを使ったプログラム、2回目は特徴色の認識ですが、
正直これだけならtwoViewは関係ありません。

ですがこれができれば、次に面白いことができます。


ということで、軽く説明いたします。
基本は、解析のところでやったことに似ています。


--- < 処理の概要 > ---

recogFeatureColor01.jpg   recogFeatureColor02.jpg   recogFeatureColor03.jpg


処理は以下のようなものになります。
1.認識したい特徴的な色を取得する。
2.カメラに映った画像を、特徴色で2値化する。
3.2値化画像に対して、各閉領域を区別する。
4.閉領域を絞り込んで、適切なものを選択する。



--- < 1.認識したい特徴的な色を取得する > ---

最初に認識したい物体の色を取得します。
この色は、周囲の色とは違う特徴的な色でなくてはいけません。

マウスで画面内の特徴色をクリックし、その色を取得します。



--- < 2.カメラに映った画像を、特徴色で2値化する > ---

次に、与えられた画像を特徴色で2値化します。
画像の全ての点の色を調べ、特徴色に近いものだけ白にして、その他は黒にします。



--- < 3.2値化画像に対して、各閉領域を区別する > ---

白い領域に対してのみラベリングを行い、各閉領域を区別します。
ここでは、異なる色で各閉領域を表しています。

またこのとき、閉領域の面積や外接矩形も計算しておきます。



--- < 4.閉領域を絞り込んで、適切なものを選択する > ---

最後に、特徴色だと判定する閾値を変えたり、
閉領域の面積が小さい・大きいものを除外したりして、目的の閉領域を求めます。

目的の閉領域が、影などにより分かれてしまっていた場合、
外接矩形を見てくっつける、なんてこともできそうです。





さて次はこれを使って、とても面白いプログラムができるはずなのですが、
勉強不足のため、なかなか上手くいきません。

ついつい、学生の頃愛用していた3Dグラフィックス数学の本を買ってしまいました。
もっと数学の勉強をしないとだめです。

ARToolKitのtwoViewを使ったプログラム、その①

カメラ間の関係を保持し、それを使ってマーカーを補間します。
ここでも、安定化と似たような計算を行います。


今回は動画では短すぎるので、画像のみです。

cameraRelate01.JPG   cameraRelate03.JPG

cameraRelate02.JPG   cameraRelate03.JPG



--- < 処理の概要 > ---

まず、どちらのカメラにもマーカーが映っている場合に、以下のような計算をします。

・"マーカー→カメラ1"、"マーカー→カメラ2" が分かっている。
・"マーカー→カメラ1"を反転して"カメラ1→マーカー"にする。
・"カメラ1→マーカー→カメラ2"という行列計算を行い、”カメラ1→カメラ2”を取得する。

次に、片方のカメラでマーカーが見つからなかった場合に、次のような計算で補間を行います。

カメラ1のみでマーカーが見つからなかった場合
・”カメラ1→カメラ2”、"マーカー→カメラ2" が分かっている。
・”カメラ1→カメラ2”を反転して、”カメラ2→カメラ1”にする。
・"マーカー→カメラ2→カメラ1"という行列計算を行い、"マーカー→カメラ1"を取得する。

カメラ2の場合も同様です。

これで、片方のカメラにさえマーカーが映っていれば、
マーカーが見えなくてもその位置を特定することができます。



--- < 処理の特徴 > ---

この方法を使うと安定化にも繋がりますが、そのために以下のような制限が付きます。

・一番最初に、2つのカメラに同じマーカーを映すなどして、変換行列を計算する。
・片方のカメラが動いた場合、変換行列を再計算する。
・両方のカメラでマーカーを発見できないときは、補間ができない。

等々です。
これを解決するためには、いくつか方法が考えられます。

1.カメラを絶対に動かさないようにする。
2.2つのカメラを固定して、変換行列を変えないまま移動できるようにする。
3.カメラ1に、マーカーとカメラ2が必ず映るようにして、カメラ2にもマーカーを付ける。

こんなところでしょうか。
他にも方法がありそうですね。



--- < 最後に > ---

上記のように、twoViewを使うには少し工夫をしないといけないようです。
ですが、そこから得られる機能には、いろんな使い道がありそうです。

作成した処理の可視化プログラムを公開いたします。

ARToolKitAlgo1.0_080510.zip


今回のプロジェクトは"Microsoft Visual C++ 2008 Express Edition"で開発いたしました。
ライブラリに、いくつかコメントを追加しましたが、不完全で間違っている可能性があります。


--- <実行ファイルの使い方> ---


○変換行列の計算プログラム

・とりあえず実行
0.カメラにマーカーが映るようにします
1.画像が表示されているウィンドウを選択して、[C]キーを押し、3Dモデルのみの画面が大きく表示されるようにします。
2.画面内で、右クリックしながら3Dモデルをズームアウトして、仮想的なカメラが表示されるようにします。
3.[1]キーを押して、仮想的なディスプレイを表示します。
4.[2]キーを押して、ディスプレイに映ったマーカーを表示します。
5.[3]キーを押して、マーカーの辺1を伸ばした面を、1つ表示します。
6.[4]キーを押して、面1の法線を表示します。
7.[5]キーを押して、辺1の向かいの辺での面と法線を表示します。
8.[6]キーを押して、2つの法線の外積を求めます。
9.[7]キーを押して、残りの面と法線を表示します。
10.[8]キーを押して、その外積を表示します。
11.[9]キーを押して、2つの外積の外積を表示します。

・その他の操作
[0]キー:処理の表示を初期状態に戻す
[b]キー:立方体オブジェクトの表示/非表示
[m]キー:マーカーオブジェクトの表示/非表示


○マーカーの認識プログラム

[1]キー:2値化した画像を表示します。
[2]キー:ラベリングした画像を表示します。
[3]キー:頂点1を表示します。
[4]キー:輪郭を表示します。
[5]キー:頂点2を表示します。
[6]キー:頂点3,4を表示します。
[0]キー:表示を元に戻します。
[c]キー:画像の位置を変更
[o]キー:輪郭線を表示/非表示
[q]キー:頂点1を表示/非表示
[w]キー:頂点2を表示/非表示
[e]キー:頂点3を表示/非表示
[r]キー:頂点4を表示/非表示

やっと2つめのカメラを購入したので、さっそくTwoViewを触ってみました。
遅くなってしまったので、コメントを頂いた方はもう解決したかもしれませんが、一応書いておきます。

基本的には、工学ナビ様のBBSで説明されている手順通りです。
詳しく書いてみます。

ちなみに僕の環境は以下の通りです。
OS      : Microsoft Windows XP Home Edition (SP2)
CPU    : AMD Athlon^(TM) 64 X2 プロセッサ 3800+
メモリ   : DDR SDRAM 1GB
Webカメラ:Qcam Pro for Notebooks ×2


1.GraphEditの入手
GraphEditは、DirectX SDKの中に入っています。
ひとまず、"C:\Program Files\"内で、GraphEditとか、graphedtで検索してみてください。
見つからない場合は、DirectX SDKをインストールしてください。


2.Webカメラのデバイス名を取得
GraphEditを起動したら、メニューから[Graph]->[Insert Filters...]を選択、ダイアログを開きます。
ダイアログのツリーから[Video Capture Source]を開き、その中の各Webカメラ名を選択します。
僕の場合は、[Qcam Pro for Notebooks]が2つあります。

各Webカメラ名を選択したときに、一番下のエディットボックスに表示される長い文字列が、そのWebカメラのデバイス名になります。僕の場合は、

@device:pnp:\\?\usb#vid_046d&pid_0991&mi_00
#6&22a7aaac&0&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\
{bbefb6c7-2fc4-4139-bb8b-a58bba724083}

@device:pnp:\\?\usb#vid_046d&pid_0991&mi_00
#6&a9d31db&1&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\
{bbefb6c7-2fc4-4139-bb8b-a58bba724083}
という文字列でした。

この文字列は、もちらんそのカメラ固有のもので、僕のカメラのものを他の人が使っても上手くいきません。


3.ARToolKitの設定ファイルを書き換える
Dataフォルダの"WDM_camera_flipV.xml"というファイルを、適当なエディタで開きます。
その中で、

<camera show_format_dialog="true" friendly_name="PGR">

という行があるはずです。これに"device_name"追加して、以下のようにします。

<camera show_format_dialog="true" friendly_name="PGR" device_name="">

ここで、先ほど取得したカメラのデバイス名を、device_nameの""内にコピーします。

<camera show_format_dialog="true" friendly_name="PGR" device_name="@device:pnp:\\?\usb#vid_046d&pid_0991&mi_00#
6&22a7aaac&0&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\
{bbefb6c7-2fc4-4139-bb8b-a58bba724083}">

次に、コピーした文字列で"&"になっている部分を"&amp;"に置き換えます。

<camera show_format_dialog="true" friendly_name="PGR" device_name="@device:pnp:\\?\usb#vid_046d&amp;pid_0991&amp;mi_00#
6&amp;22a7aaac&amp;0&amp;0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\
{bbefb6c7-2fc4-4139-bb8b-a58bba724083}">

この変更したファイルを、別名で保存します。
ここでは、"WDM_camera_flipV_01.xml"とします。

もう1つのデバイス名についても同じ作業をして、名前を変えて保存します。
こっちは、"WDM_camera_flipV_02.xml"としました。


4.プログラムを書き換える
プロジェクトを開いて、twoView.cを変更します。
"WDM_camera_flipV.xml"のところを、新しく作ったファイルに置き換えます。

#if defined(_WIN32)
        "Data\\WDM_camera_flipV.xml",
        "Data\\WDM_camera_flipV.xml",
#elif defined(__APPLE__)



#if defined(_WIN32)
        "Data\\WDM_camera_flipV_01.xml",
        "Data\\WDM_camera_flipV_02.xml",
#elif defined(__APPLE__)
に変更しました。



以上で終わりです。
僕の場合は、これでうまくいきました。

これでも失敗する場合は、残念ながら僕には分かりません。
twoViewについては、他にも解説しているサイトがあるので、そちらを参照してください。

Webカメラの種類も関係あるみたいです。




※追記 

○08/05/09

一方のカメラのフレームレートだけ、やけに遅い問題が発生していましたが、
"videoWin32DirectShow.cpp"ファイルの

const long                frame_timeout_ms = 0L;
というのを

const long                frame_timeout_ms = 100L;
ぐらいにしたら、直りました。数値は適当です。


○08/05/10

一方のカメラの画面が上下反転していた問題がありました。
調べてみると、"WDM_camera_flipV_02.xml"ファイルだけ、

<RGB32 flip_h="false" flip_v="true"/>


<RGB32/>
となっていたのが原因でした。
このファイルを作るのに、"WDM_camera.xml"を利用したのが間違いだったみたいです。

解析の2回目は、マーカーの認識についてです。
前回の変換行列の計算で、省略した部分を説明します。



---- < マーカー認識の概要 > ----


※注意
この動画で、画像の色分けでは、そのつど色が計算されるため、多くの色が点滅するような動画になっています。
また、画像の生成等の重い処理を行っているので、フレームレートは低くなっています。

光過敏性発作などがある方は、予めご注意ください。





BGM:エコテロニカ(sansuiさん)

なんだかムーンサイドみたいですね。
ちょっと誤字があるようですが、気にしないでください。


ARToolKitでは、変換行列を計算する前に、その基となるマーカーを知っていなければなりません。
カメラに映った画像から、どこにマーカーがあるのか判定するために、おおまかに以下のような処理を行います。


1.カメラからの画像を2値化して、画像の暗い部分を探す
2.暗い部分で、それぞれの閉じた領域に印を付ける
3.各閉領域で、一番端の点を最初の頂点(頂点1)とする
4.頂点1から、領域の輪郭を探す
5.輪郭が分かったら、2番目の頂点を探す
6.残りの頂点3,4を探す
7.4つの頂点をもつ領域を4角形と判断する
8.4角形内の画像を単純化する
9.単純化された画像に対して、パターンマッチングを行う

それぞれの処理を見てみます。



---- < 1.カメラからの画像を2値化して、画像の暗い部分を探す > ----

カメラから得られたカラー画像を、2値化して白or黒のみの画像にします。
ARToolKitでは、黒枠のマーカーを認識するので、
ここでの画像は白黒を反転したようなものになっています。



---- < 2.暗い部分で、それぞれの閉じた領域に印を付ける > ----

画像を2値化すると、閉じた領域がたくさんできます。
それぞれの閉領域を区別するために、ラベリングと呼ばれる作業を行います。

これは、各領域を走査して、繋がっている部分に同じ番号を割り振っていく作業になります。



---- < 3.各閉領域で、一番端の点を最初の頂点(頂点1)とする > ----

2で閉領域が見つかったので、各閉領域の外接矩形を求めます。

そして、外接矩形の辺上にある点を探します。
これが、最初の頂点(頂点1)になります。



---- < 4.頂点1から、領域の輪郭を探す > ----

次に、輪郭を探します。
頂点1からスタートして、閉領域の輪郭を辿るように、点を見つけていきます。
最後に、頂点1に戻ってきます。



---- < 5.輪郭が分かったら、2番目の頂点を探す > ----

輪郭は点の集まりなので、その中で頂点1から最も離れたものを探します。
それを頂点2とします。



---- < 6.残りの頂点3,4を探す > ----

頂点1、2から頂点3,4を探します。
まず輪郭点を、"頂点1→2" と "頂点2→1" の2つに分けます。

2つの輪郭点で、頂点1・2の線分から、最も離れた点を探します。
これを再帰的に繰り返して、残りの頂点も見つけ出します。



---- < 7.4つの頂点をもつ領域を4角形と判断する > ----

上記の処理の途中で、領域が望みの4角形かどうかが、だいたい判定されます。

最初に、面積が非常に小さい、または大きい領域は除外されます。
他にも、4つの頂点がうまく見つからない領域も除外されます。

4つの頂点は、順番に並んでいるとは限らないので、
そのつど調整されます。



---- < 8.4角形内の画像を単純化する > ----

4角形が見つかったので、やっとパターンの判別に入ります。
判別のために、4角形内の画像は単純かされます。

マーカーが斜めに映っている場合も、内部の画像は修正され、真正面からのものになり、
解像度も非常に小さくなります。



---- <
9.単純化された画像に対して、パターンマッチングを行う > ----

この単純化された画像に対して、パターンマッチングを行います。
パターンマッチングでは、基となるパターンと単純化された4角形内の画像を比較し、誤差を計算します。

この誤差が、ある決まった値より小さい場合に、これが求めるマーカーであると判定されることになります。
(実際には、最も誤差が小さいパターンが、その4角形に割り当てられ、後の判断はプログラマに委ねられます。



---- < 最後に > ----

調べてみて分かりましたが、すばらしいアルゴリズムですね。
非常に勉強になりました。

やはり、所々怪しいところはありますので、間違い等はご指摘いただければありがたいです。



あまり関係ないですが、BGMを使用させてもらっているsansuiさんつながりで、「ゆめにっき」というフリーゲームを現在やっています。
RPGツクールで作られた、夢の中を探索するという戦闘のないゲームなんですが、「とても怖いゲーム」です。
まるで、マザー2のムーンサイドのような怖さで、今回作った動画もプログラムもそれっぽいと思ってしまいました。



このアーカイブについて

このページには、2008年5月に書かれたブログ記事が新しい順に公開されています。

前のアーカイブは2008年4月です。

次のアーカイブは2008年6月です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。

Powered by Movable Type 4.01a