Pipe Renderでタグ「ARToolKitのtwoView」が付けられているもの

お待たせしました。
twoViewを使った、ステレオマッチングプログラムのソース公開です。

StereoAnyColor1.0.zip


--- < プログラムの使い方 > ---


0.Webカメラが2つあることが最低条件です。
ちなみに僕のは"Qcam Pro for Notebooks"。他のカメラでは試していないので、動くかどうかはわからないです。
あと、2つのカメラの設定を同じにしてください。
1.2つのカメラの向きを平行にして、まっすぐに並べる。
2.赤・黄・青など特徴的な色の物体を用意し、場所は白いテーブルの上など選んだ色が他にはないような所にする。
3.TwoViewに関する説明を読み、"WDM_camera_flipV_01.xml"、"WDM_camera_flipV_02.xml"を作成。
4.プログラムを起動して"Video Source 1"ウィンドウで、用意した特長的な色の物体を画面に表示して、それを左クリックします。
5.物体が画面に映っている状態で、Fキーを押してラベリング画像を表示。
6.Kキーを押して続けて閾値を下げ、目的の物体が一番大きくラベリングされるようにします。
7.押しすぎて全くラベリングされなくなったら、Jキーを押して閾値を上げます。
8.もう1つの物体を認識させたいときは、右クリックで画面上の物体の色を指定します。
9.2つの物体が一番大きくラベリングされるようになったらOKです、Fキーを押して元の画面に戻ります。
10.マーカーを表示し、マーカーと2つの物体の距離が表示されることを確認します。
11.2つの物体の距離を近づけて、カーソルがクリック状態になるかどうか(2つの物体間の線が赤くなる)を確認します。
12.マーカー上の立方体にカーソルを重ねて、クリック状態にします。
13.クリック状態でカーソルを移動すると、立方体も移動します。
14.立方体の移動中にクリックを解除すると、立方体の移動が止まります。

以上です。
まだ色の識別が甘いので、上手く認識しないかもしれません。
今後の課題です。


--- < ソースの概要 > ---

今回のプログラムでは、いくつかのクラスを追加しました。
・CCamerasRelationクラス:カメラ間の関係
・CStereoAnyColorPointクラス:指定色のステレオ処理を行う
・CFindColorPosInImgクラス:画像認識を行い、指定色のスクリーン上の座標等を計算
・CCamSimpleTriangulationクラス:3角測量を行う

以上のクラスは次のように使います。
1.インスタンスの定義
2.クラスの初期化
3.画像認識の計算
4.結果の取得


--- < 1.インスタンスの定義 > ---

改良したtwoView.cでは、以下のようにクラスのインスタンスを作成します。
CCamerasRelation    gCamRelate(CONTEXTSACTIVECOUNT);
CStereoAnyColorPoint g_stereoOperator;
今回はグローバル変数で定義しました。


--- <
2.クラスの初期化 > ---

次に、この変数を初期化します。
// グローバル変数の初期化
static void InitGlobalValue()
{
    // 画像認識の色を指定
    g_stereoOperator.ClearTargetColor();
    g_stereoOperator.AddTargetColor( g_cnColorRealRed );
    g_stereoOperator.AddTargetColor( g_cnColorRealYellow );

    // カメラの投影行列
    gCamRelate.SetCamParam( 0, arParam.mat );
    gCamRelate.SetCamParam( 1, arParam.mat );
}
CStereoAnyColorPointの初期化では、指定色をAddTargetColorで追加します。
CCamerasRelationの初期化では、SetCamParamで各カメラに透視投影行列を設定します。


マーカーを認識できた時点で、もう1度別の初期化を行います
CCamerasRelationで、カメラ間の関係を計算します
// 2つのカメラが、同じマーカーを認識できてるかどうか
if ( gContextsActive[0].id == gContextsActive[1].id )
{
     // カメラ1の変換行列を保存
     CopyArray3x4ToMatrix4x4( mtrxTemp1, gContextsActive[0].patt_trans );
     CopyArray3x4ToMatrix4x4( mtrxTemp2, gContextsActive[1].patt_trans );

     gCamRelate.CalcRelation(0, 1, mtrxTemp1, mtrxTemp2 );
}
CStereoAnyColorPointでは、新しいカメラ画像をセット
g_stereoOperator.InitImgSource(    arImXsize, arImYsize,
                        gContextsActive[0].ARTImage,
                        gContextsActive[1].ARTImage );



--- < 3.画像認識の計算 > ---

必要な情報をセットできたら、画像処理を行います。
g_stereoOperator.RecognitionColor3DPos(&gCamRelate);
画像処理では、カメラの関係を引数として指定します。


--- < 4.結果の取得 > ---

計算が上手くいったら、結果の3次元ベクトルを取得します

for ( int iTarget = 0 ; iTarget < g_stereoOperator.GetTargetPosCount() ; iTarget++ )
{
    double dPos[3];
    if ( !g_stereoOperator.GetTargetPos(iTarget, dPos) )
        continue;
}
GetTargetPos(const int ciTarget, double dPos[3])で、指定色のベクトルを取得できます。




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値も入れた距離で計算したら上手くいきました。
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を使うには少し工夫をしないといけないようです。
ですが、そこから得られる機能には、いろんな使い道がありそうです。