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

パブリックドメインソースを公開したので、次にプログラムをまとめたものを公開します。

FingerDetect1.0.zip


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

0.Webカメラが2つあることが最低条件です。
ちなみに僕のは"Qcam Pro for Notebooks"。他のカメラでは試していないので、動くかどうかはわからないです。
あと、2つのカメラの設定を同じにしてください。
1.2つのカメラの向きを平行にして、まっすぐに並べる。
2.緑色のキャップのようなもの(作者は風船を使用)を用意し、それを親指に付けます。
3.TwoViewに関する説明(http://render.s73.xrea.com/pipe_render/2008/05/artoolkittwoview.html)を読み、"WDM_camera_flipV_01.xml"、"WDM_camera_flipV_02.xml"を作成し、Dataフォルダに入れる。
4.マーカーと手を表示し、マーカーと指の距離が表示されることを確認します。
5.親指と人差し指を近づけて、カーソルがクリック状態になるかどうか(2つの指の間の線が赤くなる)を確認します。
6.マーカー上の立方体に指近づけて、クリック状態にします。
7.クリック状態で指を移動すると、立方体も移動します。
8.立方体の移動中にクリックを解除すると、立方体の移動が止まります。



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

今回のプログラムでは、いくつかのクラスを追加しました。
・CHandContourクラス:手の輪郭線を扱います。指の認識などを行えます。
・CPointActionクラス:複数の点を用いたカーソルアクションを行います。

こちらについては、近いうちにドキュメントを公開する予定です。



ソースの公開ですが、まず最初に新規に作成した指認識のソースだけ公開いたします。
これは一応ライセンス上の体裁を整えるためだけの行為なので、この後にまとめたソースをちゃんと公開いたします。

というのも、このソースについてはGPLライセンスではなく、パブリックドメインになっています。
なので、この部分だけ分離し、先に公開しました。

(実際にはここまで厳密にやらなくてもいいと思いますが。


指認識部分のソース:
CHandContour1.0.zip



パブリックドメインソフトウェア(PDS)については以下のよう説明されています。
Wikipedeia:パブリックドメインソフトウェア

ここで、日本では著作人格権を放棄できないので、以下のようにしなくてはいけないと書かれています。

...「将来にわたって著作権(及び著作者人格権)を主張しないことを宣言する」などと明記することによって、事実上の PDS として扱われる...

これによりこの部分のソースについては、利用者は著作権による制限なしにソフトウェアを利用することができます。GPLのような「ソース公開の義務」も発生いたしません。


それから今回、コメントをdoxygenの形式に対応いたしました。近いうちにドキュメントを作成し、公開する予定です。

指が認識できたら、これをポインティングデバイスとして利用します。

これで、普段僕らがやっている「手で掴む・離す」という作業をそのままUIとして利用できるので、より自然な操作が可能になるはずです。




--- < 概要 > ---

今回、「つまむ」という動作を検出するために、以下の2つが必要になりました。

・親指の判断
・指がくっついた状態でも手の領域が重ならないようにする

この問題を解決するために、親指に緑色のキャップを装着しました。

これで、指先に緑の領域がある場合は親指であると判定でき、さらに指がくっついた状態でも、キャップの緑が邪魔をして肌色領域が混ざるのを防ぐことができました。

ここで指がくっついた状態では、親指じゃない方の指が親指だと判定される現象が発生しましたが、そのときの2つの指の座標はほぼ同じになるので、あまり問題ありませんでした。



ポインティングのために行った処理を説明します。

1.指を認識する
2.親指を探す
3.親指と他の指との距離を測る
4.距離がある程度近い場合はドラッグ開始
5.ドラッグ中に距離が離れたら、ドラッグ終了

それぞれの詳細は以下の通りです。



--- < 1.指を認識する > ---

指の認識は、前回の処理とほぼ同様です。
今回追加した処理では、左右のカメラで指を一致させるために、指のマッチングを行いました。

左右画像での指のマッチングは単純で、基準の位置座標を各指を元に変えながら、その他の指の距離を測定し、最も近いものを探しているだけです。

マッチングで指先だけでなく、指の付け根も比較対象に加えることで、マッチングの精度が上がりました。さらに指認識の精度も上がります。

finger_match01.jpg



--- < 2.親指を探す > ---

親指には緑のキャップがあるはずなので、各指先でその緑を探します。
そして、最も緑の領域が多い指を親指であるとします。

find_thumb_01.jpg

また、親指のマッチングも行います。

match_thumb_01.jpg



--- < 3.親指と他の指との距離を測る > ---

左右の画像で一致した指の座標が取得できたので、前回と同様三角測量で指の3次元座標を計算します。

全ての指の3次元座標が分かったら、親指とその他の指との距離を計算します。そして、距離が最も近い指を探します。



--- < 4.距離がある程度近い場合はドラッグ開始 > ---

近い指までの距離が分かったら、その距離がある値より小さいかどうか調べます。そして、小さいときに「つまんでいる状態」のフラグを立てます。

「つまんでいる状態」で立方体との衝突判定を行い、
衝突していたら、ドラックを開始します。

ドラッグ中は立方体が指に追従して移動します。



--- < 5.ドラッグ中に距離が離れたら、ドラッグ終了 > ---

親指と近傍の指との距離が一定値より離れた場合、
「つまんでいる状態」フラグを下げます。

ドラッグ中に「つまんでいる状態」フラグが下がったら、ドラッグを中止します。これでドロップができます。

最後のドラッグ&ドロップは、前回の色認識ポインティングと同様です。


最近はARToolKitのプログラムも少しできてきたので、
次は手とかをそのまま認識させたいと思っていました。

そしたらちょうどmasafumiさんという方のブログ手認識を使ったARという記事を見つけました。
この方法は認識精度が高そうなので、twoViewでの物体認識にも使えそうです。


この手認識ARの研究は、手を認識することによってマーカーの代わりにしようというものです。
ソースも公開されているので、すぐにこのプログラムを使った動画がアップされています。



見ての通り、指認識の精度は非常に高いです。

というわけで今回は、この指認識のアルゴリズムだけをいただき、
この情報を元にtweVIewから指の3次元座標を計算してみました。

これで綿棒や色の付いた目印を使う必要がなくなります。


disttrans01.jpg   labeling01.jpg   finger02.jpg   finger3d01.jpg 



--- < 指認識の概要 > ---


指認識では、おおまかに以下のような処理を行っています。

1.手の色に近い領域を探し、輪郭線で分ける
2.距離変換画像を作成する
3.輪郭線を使ったラベリング
4.手の輪郭のカーブ具合を調べる
5.カーブ具合から指の判定

僕が感動したのは、手の輪郭線から指を判定する処理です。



--- < 1.手の色に近い領域を探し、輪郭線で分ける > ---

やはり最初は手の色を判定し、それを元に2値画像を作成します。

元のプログラムではここでRGBをYCrCbという色空間に変換し、
ヒストグラムなどを使って肌色を判定していました。

ですが、僕のプログラムでは前回のHSV色空間を使用しました。

そしてさらに、この肌色の2値画像から輪郭線情報を作成します。
輪郭線はOpenCVのcvFindContoursを使用して作成します。



--- < 2.距離変換画像を作成する > ---

次に、2値化画像から距離変換画像を作成します。
距離変換とは、値のある現在の点から値のない点への最短距離を求める計算です。

この最短距離を画像に書き込むと、上の1つめの画像のようになります。
この距離変換によって、肌色に近い領域で一番大きなものが大体分かります。

今回は、「その一番大きな領域が手である」という判定をしています。



--- < 3.輪郭線を使ったラベリング > ---

この手の領域を判別するために、輪郭線を使用します。

1.まっさらな画像を用意
2.画像に対し、各輪郭ごとに内部を塗りつぶしていく
3.塗りつぶすたびに、「距離変換の値が最大となる座標」が塗り潰されたかどうか判定する。
4.もし塗りつぶされいれば、その輪郭が「求める手の領域」のものになる。

この処理によってラベリングを行わずに、最大面積の領域を判定できてしまいます。
ラベリング処理は重いものが多いので、これはとても便利です。

結果的に上の2つ目の画像のようなものができあがります。



--- < 4.手の輪郭のカーブ具合を調べる > ---

手の輪郭を取得できたので、次にこれを用いて指を判定します。
指判定には、各輪郭点の狭い範囲で内積と外積を計算します。

1.輪郭線上の全ての点を調べる
2.各点の狭い範囲で、先の輪郭点へのベクトルと、後の輪郭点へのベクトルを取得する。
3.2つのベクトルの内積を計算し、それがある程度大きければ、その点はカーブしていると判定
4.2つのベクトルの外積を計算し、そのカーブの方向を判定
5.調べる範囲を変えて、2~4の処理を繰り貸す。
6.求める値になったら、そのカーブが指に似た曲がり具合であると判断する。

この処理で、上の3つ目の画像ができあがります。



--- < 5.カーブ具合から指の判定 > ---

上記の処理で指っぽいカーブは分かりましたが、これが本当に指かどうかはまだ分かりません。
また、場合によってはその指がどの指なのかも判定が必要です。

ですが、今回のプログラムではその処理を入れていません。
ここでは最後に、前回同様ステレオでこの2次元座標を3次元に変換して終わりです。

これで上の最後の画像のようになります。


元の研究では、事前に指の理想的な位置を取得しておいて、
それと比較することで各指を認識したりしているようです。

僕のプログラムも指っぽい形状の認識の精度は高くなりましたが、
その後の指判定はまだできていません。


ソースの清書も含め、その辺が今後の課題となります。


新しいプログラムは「物体認識」とか凄そうな名前を付けましたが、
基本的にはtwoViewを使ったプログラムの延長です。

今回は、前回のプログラムの色認識を改良しました。
少しずつ純粋なARToolKitから離れてきています。


--- < HSV色空間について > ---

HSVなんて聞きなれない単語ですが、簡単に言うとRGBの親戚みたいなものです。

知っての通り、RGBは「赤・緑・青」の色を組み合わせて多くの色を表現しますが、
HSVでは代わりに「色相・彩度・明度」という属性を組み合わせることで色を作ります。

詳しくは、Wikiを参照してください。


なぜRGBじゃなくてHSVを使うのかというと、こっちの方が特定の色を見つけやすいからです。

Wikiを見てもらえば分かるように、HSVでは赤とか青とかの情報は色相を見れば大体分かります。
残りの彩度や明度は、言ってみれば明るさや暗さみたいなもので、ほとんど無視していいものです。

逆に言えば「明るい赤」も「暗い赤」も、同じ赤として認識してくれることになります。
実際には、物体の「影の部分」や「光が反射している部分」まで認識してくれる可能性がある、
ということです。



--- < 実行結果 > ---

今回は、このHSV色空間で画像を扱うために、OpenCVというフリーの画像処理ライブラリを使用しました。
また指定色の物体は綿棒ではなく、色風船の端を切って指にはめてみました。

LabelRect01.jpg   Labeling01.gif   pointing01.jpg  

HSV色系を用いる以外の処理は、今までと一緒です。
とりあえずはうまくいっているようです。


しかし、欠点もあります。
HSV色系はそのままだと感度が良すぎて、余計なものまで認識してしまいます。

上の画像では、閾値を狭くしたので指の先を正しく認識できていません。
そこで、閾値を広くすると下の画像のようになります。

LabelRect02.jpg   Labeling02.gif

閾値が広いと指の部分を正しく取得できますが、同時に関係ない部分まで誤認してしまっています。

このような結果にならないように、「彩度・明度」も考量しなくてはならず、
「色相」の閾値も、そのつど微調整が必要です。

またこれまで以上に、撮影環境に気を使わなくてはいけないかもしれません。


この辺は今後の課題です。

 

お待たせしました。
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値も入れた距離で計算したら上手くいきました。
日々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のムーンサイドのような怖さで、今回作った動画もプログラムもそれっぽいと思ってしまいました。



安定化の次は、プログラムの高速化などをやってみようと思ってましたが、
高速化のためには、ARToolKitのソースをもっと理解していなければなりません。

そこで、次に「ARToolKitの解析」を行うことにしました。


解析のその1は、変換行列の計算アルゴリズムの解説をやってみます。
ここでいう変換行列とは、マーカー(オブジェクト)座標系から、グローバル(カメラ)座標系へ変換する行列のことです。

これは、ARToolKitの重要な仕組みの1つです。



---- < 変換行列計算の概要 > ----



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

 OpenGLなどの3DCGでは、3Dモデルの移動・回転などを行うために、座標系の変換行列を用います。
ARToolKitの場合も、この変換行列がないと、マーカー上にモデルを表示できません。

プログラムでは、スクリーン上に映ったマーカーの画像から、この変換行列を計算しています。
計算のプロセスは、大まかに以下のようになります。

1.マーカーの黒い四角形を認識する
2.四角形の枠である、4辺を計算する
3.それぞれの辺を、カメラの投影方向に伸ばし、面を作る
4.面の法線を計算
5.向かい合った面同士の法線から、外積を計算する
6.その外積同士から、さらに外積を計算
7.現在わかっている式を用いて、行列の残り値を計算する


今回は"スクリーン上の4角形の4辺"から、"変換行列の3×3の要素"を計算するとこまでを中心に、解説していきます。



---- < 1.マーカーの黒い四角形を認識 > ----

四角形の認識ではまず、カメラに映った画像を2値化(白黒に)します。
そして、その白黒画像から、4角形を探します。
さらに、見つけた4角形が登録されているマーカーかどうか調べます。

この部分の詳しいアルゴリズムについては、後日解説するつもりです。



---- < 2.四角形の枠である、4辺を計算する > ----

ここも、1と一緒に解説いたします。



---- < 3.それぞれの辺を、カメラの投影方向に伸ばし、面を作る > ----

4角形の辺が取得できたら、この辺を伸ばして、面にします。
伸ばし方は、辺がスクリーンへ投影された方向に伸ばします。

つまりこの面は、3次元空間上のマーカーの4辺も通ることになります。
カメラの視点、2Dのマーカーの辺、3Dのマーカーの辺を繋ぐ面です。



---- < 4.面の法線を計算 > ----

それぞれの面の法線(面に対して、垂直なベクトル)を計算します。



---- < 5.向かい合った面同士の法線から、外積を計算する > ----

法線が計算できたら、向かい合った面同士の法線から、外積を計算します。
外積は、2つの法線に対し垂直になります。

この外積は、マーカー座標系の1つの軸を表すベクトルになります。



---- < 6.その外積同士から、さらに外積を計算 > ----

さらに、外積同士の外積をとります。
この3つの外積が、それぞれマーカー座標系のX軸, Y軸, Z軸になります。

さらに値を補正すると、変換行列の3×3の要素になるわけです。



---- < 8.現在わかっている式を用いて、行列の残り値を計算する > ----

変換行列の3×3の要素は、回転や拡大縮小を表しています。
変換行列に必要な残りの要素は、平行移動です。

平行移動分を計算するには、それまでに用いられた行列等の式を使い、答えを出します。



以上が、僕が理解できた範囲でのアルゴリズムの説明です。
間違いや不足があった場合には、連絡をお願いします。


お待たせしました。ソースを公開いたします。
時間がかかってしまい、申し訳ありません。

また、作者も非常に経験不足ゆえ、ファイルのミス、プログラムの不具合、説明不足、コードが読みにくい、等々予期せぬ問題が発生するかと思われます。

そういった問題は、可能な限り改善していきたいと思いますので、
メールなどで、できるだけ詳細な連絡(動作環境、現象の発生手順等)をいただけると非常にありがたいです。

では、Ver1.0になります。

MultiRelate1.0.zip
こちらも、Readmeの詳細説明用に使用いたします。

プログラムの大まかな処理は、その①その②を見てもらっても大体はわかります。
今回は少しプログラム寄りな説明になります。

安定化プログラムでは以下のような処理を行っています
・設定ファイルを読み込む
・通常表示
・関係値の計算
・計算結果を表示する
・補完処理を加えた表示
・関係値の保存

このプログラムでは、関係値のデータと処理を行うクラス"CObjectMultiCreator"があり、
上記の処理のほとんどは、このクラスのメンバ関数内で行っています。



では、それぞれの処理を見てみます

・設定ファイルを読み込む : 関数 LoadMultiRelationInf
設定ファイルには、"複数オブジェクトファイルへのパス"と、"関係値の値"が保存されています。
初期状態では"関係値の値"は存在しません。
詳しくは、その④-EXEの使い方を参照してください。


・通常表示
通常表示では、従来のARToolKitとほぼ同様の処理を行っています。


・関係値の計算 : 関数 CalcAllMarkerRelate
キー操作により、編集モードに入ったときに、関係値の計算が行われます。
関数に入る前に、従来と同じ方法で、各マーカーの座標変換行列  "object.trans" が計算されます。

ここでマーカーA, Bが見つかったとします。
そのとき次のような計算を行います。

1.座標変換行列、"A→カメラ"と、"B→カメラ"、が分かっている。
2.1の"B→カメラ"を反転して、"カメラB"にする。
3.1と2から、"A→カメラB"という行列計算を行う。
4.3から"A → B"という座標変換行列を得る。

平均値計算用に、サンプル数と行列の合計値を、メンバ変数に蓄えておきます。

ある程度、サンプル数が溜まったら、上記と同じ方法で誤差を計算します。
これも、サンプル数と合計値の形で、持っておきます。


・計算結果を表示する
計算が大体終了したら、それを表示し、ユーザーに知らせます。
ユーザーはこの表示を見て、計算の頃合を計り、編集モードを終了します。

表示に使用される値は、マーカー関係情報の構造体"MARKER_RELATE_INFO"の、誤差の合計値"dError"や、サンプル数"lRelCount"を使用します。


・補完処理を加えた表示  : 関数 GetGLTransFromRelate
関係値が計算できても、マーカーを問題なく取得できた場合には、通常の描画を行います。
問題は、マーカー情報が正しく取得できなかった場合です。

例えば、マーカーAの情報が取得できず、マーカーBは取得できたとします。
その時は、以下のような計算になります。

1.座標変換行列 "A →B"と"B → カメラ" が分かっている
2.1より、" A → B → カメラ" という行列計算を行う
3.2の結果から、"A → カメラ" という座標系変換行列を得る

というような感じです。


・関係値の保存 : 関数 SaveMultiRelationInf
最後に関係値の保存を行います。
ファイルにデータとして保存してしまえば、時間使用時、又は他のプログラムでも再利用できます。
実行のたびに関係値を計算する手間を、省けるわけです。



更なる詳細については、プログラムを読んだり、デバック実行して、理解していただくか、
それでも分からない場合は、メールにてご連絡ください。
Readmeの詳細説明に必要なので、ソース公開前に書いておきます。
実行ファイルの使用方法です。


--- < とりあえず実行してみる > ---


0.GULTをインストール
 実行にはGLUTが必要です。

1.マーカーを印刷
 \patternsフォルダ内の、マーカーを印刷します。
 印刷できない場合は、ディスプレイにマーカーの画像を表示するだけでも、大丈夫です。

2.実行ファイルを起動
 \binフォルダ内の"MultiRelate1.0.exe"を実行します。
 設定ダイアログが出て、Webカメラから画像が表示されるはずです。

3.確認
 マーカー上に色のついた立方体が表示されるはずです。

4.編集モードにする
 キーボードの"E"キーを押して、編集モードにします。
 操作キーは、画像が映っているウィンドウを選択していないと、実行されません。

5.関係値のリセットを行う
 キーボードの"C"キーを押して、関係値をリセットします。

6.関係値を設定する
 できるだけ多くのマーカーが認識されるように、カメラを移動してください。
 そして表示が安定するまで、その場でカメラを動かさないようにしましょう。
 立方体の線が緑や黄色で安定したら、だいたい計算ができています。

7.全てのマーカーで、6の作業を行う
 6の作業を、全てのマーカーに対して行います。
 2つ以上のマーカーが認識されていないと意味がありません。

8.通常モードに戻す
 もう一度"E"キーを押して、通常モードに戻ります。

9.関係値の確認
 関係値が正しく計算できていれば、1つのマーカーの認識に失敗しても、他の成功したマーカーから補完されます。

10.保存する。
 "S"キーを押して、関係値の保存をします。
 プロンプト(文字しか表示されない、もう一つの黒い画面)に、保存ができたという旨の文章が表示されれば、完了です。
 再実行した時にも、保存された関係値を使用し、何度も計算する必要がなくなります。



--- < 使い方の詳細 > ---

○キー操作

・"E"キー:[編集モード]/[通常モード]への切り替えを行います。
・"C"キー:計算された関係値をリセットします。
・"S"キー:関係値を保存して、次回も使用できるようにします。
・"1~9"キー:1~9番の、マーカー上の3Dモデルの[表示]/[非表示]を切り替えます。
・"0"キー:全ての3Dモデルの[表示]/[非表示]を切り替えます。
・"R"キー:マーカー間の関係を表す線の[表示]/[非表示]を切り替えます。
・"M"キー:マーカー自体を表す、四角形の印の[表示]/[非表示]を切り替えます。
・"V"キー:現在表示されている3Dモデル間の関係値のみをリセットします。
・"T"キー:文字情報の[表示]/[非表示]を切り替えます。


○マーカー間の関係を表すファイル ”Data\MultiRelationInf.dat”
ファイルの内容は、概ね以下のようになっています。

#マーカーオブジェクトデータ
Data/multi/markerColor30_01_6.arobj

#マーカーの関係データがあるかどうか
1

#################################################################
#marker 1
#to 1
0
0.000000 0.000000 0.000000 0.000000
0.000000 0.000000 0.000000 0.000000
0.000000 0.000000 0.000000 0.000000

#err
0
0.000000 0.000000 0.000000 0.000000
0.000000 0.000000 0.000000 0.000000
0.000000 0.000000 0.000000 0.000000
#Sum
-1.000000

#to 2
602
-601.079477 -6.103214 -29.765651 -224.731229
29.999639 -22.392234 -600.762449 -17661.005934
5.014032 -601.428488 22.542861 -21332.142015

#err
503
502.913258 -4.899541 2.086850 -469.029122
4.890394 502.880013 2.277454 -35.750323
-2.163808 -2.263550 502.959077 -328.080689
#Sum
4.299248

#to 3
    ・
    ・
    ・


最初に、複数のオブジェクトを記述したファイルのパスを書きます。
このファイルは既存のプロジェクト"loadMultiple"で使用されているのと、同じ形式なります。

自分で作ったマーカーを利用する場合には、この複数オブジェクトファイルの内容や、ここのパスを変更してください。

次に、マーカー間の関係値が事前に保存されているかを示すフラグが書かれています。
初期値は0になっていて、関係値を保存した後は1になります。
この値が0の場合は、後に関係値が続いていても読み込みません。

最後に、実際の関係値が書かれます。
ここに書かれる関係値は、
・全てのオブジェクトから全てのオブジェクトへの座標変換行列(サンプル数と合計値)
・その行列の誤差(サンプル数と合計値)
・誤差を合計した値
になります。見ての通り、非常に冗長です。

実際の関係は、各合計値をサンプル数で割った平均値が用いられます。
さて、いよいよソース公開の作業に入ります。
最初にGPLの詳細説明と、Readmeの作成についてです。

----------------------- < GPLの詳細 >
-----------------------

GPLについて、補足説明をさせていただきます。
自分がGPLについて、実際にどうソースを変更したかについてです。


○GPLの内容が書かれた文を配布ファイル内に入れる
ARToolKitにもともとあった"COPYING.txt"と、その日本語訳の文を、ファイルに付属しました。


○ファイルを変更した旨とその変更日とを、変更したファイル上に明確に表示すること。
これに関しては、従来のコメントの書き方で対応させていただきました。
ファイルの先頭のコメントで、以下のようなものを追加します。

/*******************************************************************************
 *
 * \file    object.h
 *
 * \brief    オブジェクトに関する情報と操作
 *
 * \date    08/02/02    PipeR    構造体にcf等の付加情報を追加しました
 *
*******************************************************************************/
又は、新規作成の場合は
/*******************************************************************************
 *
 * \file    MultiSetting01.c
 *
 * \brief    複数マーカー認識で用いる、
 * \brief    MultiMarkerInfoの設定ファイルを作成する
 *
 * \author    PipeR
 *
 * \date    08/02/02    PipeR    作成
 *
*******************************************************************************/
一番下の\dateで、「日付・名前・変更内容」を記述します。
コメントはDoxygen方式になっています。


○ソース内の著作権表示と無保証等の説明
追加したコメントは以下のような内容になります

/*******************************************************************************
 *
 *   Copyright (c) 2008 PipeR
 *
 *   The distribution policy is described in the file "COPYING.txt" furnished
 *    with this library.
 *
 *    本プログラムは、GNU 一般公有使用許諾に準拠します。
 *    利用も配布も商用利用も自由ですが、著作権は放棄しておりません。
 *    また、改変も自由ですが、GPLである以上、改変バージョンの配布を行う際には、
 *    ソースの公開は必須条件となりますので、ご注意下さい。
 *    GNU 一般公有使用許諾については、付属の"COPYING_JPN.txt"をご覧ください
 *
 *
 * 本プログラムはフリー・ソフトウェアです。あなたは、Free Software
 * Foundation が公表したGNU 一般公有使用許諾の「バージョン2」或い
 * はそれ以降の各バージョンの中からいずれかを選択し、そのバージョン
 * が定める条項に従って本プログラムを再頒布または変更することができ
 * ます。
 *
 * 本プログラムは有用とは思いますが、頒布にあたっては、市場性及び特
 * 定目的適合性についての暗黙の保証を含めて、いかなる保証も行ないま
 * せん。詳細についてはGNU 一般公有使用許諾書をお読みください。
 *
 * あなたは、本プログラムと一緒にGNU 一般公有使用許諾の写しを受け取っ
 * ているはずです。そうでない場合は、Free Software Foundation, Inc.,
 * 675 Mass Ave, Cambridge, MA 02139, USA * へ手紙を書いてください。
 *
 *    ----------------------------------------------------------------------
 *    * 【注意】 現在、このバージョン2の発行者(FSF)住所は、正式に新
 *     しい住所の 51 Franklin St, Fifth Floor, Boston, MA 02110-1301,
 *     USA に変わっている。
 *    ----------------------------------------------------------------------
 *
*******************************************************************************/
この内容は、GPLの日本語訳に従っています。


○実行ファイル内での、著作権・無保証等の表示
これも、GPLの日本語訳に従い、プログラム実行直後に以下のプログラムを実行

printf("ARToolKitの安定化プログラム Ver1.0 Copyright (c) 2008 PipeR\n");
printf("ARToolKitの安定化プログラム は完全に無保証です。詳細はOpenGLのウィンドウで\"G\"キーをタイプしてください。\n");
printf("これはフリー・ソフトウェアなので、特定の条件の下でこれを再頒布することができます。詳細は付属の\"COPYING.txt\"か\"COPYING_JPN.txt\"をご覧ください。\n");

もちろん、"G"キー押下時にも以下の文を加えます。

        printf("ARToolKitの安定化プログラム Ver1.0 Copyright (c) 2008 PipeR\n\n");
        printf("he distribution policy is described in the file \"COPYING.txt\" furnished with this library.\n\n");
        printf("本プログラムは、GNU 一般公有使用許諾に準拠します。利用も配布も商用利用も自由ですが、著作権は放棄しておりません。また、改変も自由ですが、GPLである以上、改変バージョンの配布を行う際には、ソースの公開は必須条件となりますので、ご注意下さい。GNU 一般公有使用許諾については、付属の\"COPYING_JPN.txt\"をご覧ください。\n\n");
        printf("本プログラムはフリー・ソフトウェアです。あなたは、Free Software Foundation が公表したGNU 一般公有使用許諾の「バージョン2」或いはそれ以降の各バージョンの中からいずれかを選択し、そのバージョンが定める条項に従って本プログラムを再頒布または変更することができます。\n\n");
        printf("本プログラムは有用とは思いますが、頒布にあたっては、市場性及び特定目的適合性についての暗黙の保証を含めて、いかなる保証も行ないません。詳細についてはGNU 一般公有使用許諾書をお読みください。\n\n");
        printf("あなたは、本プログラムと一緒にGNU 一般公有使用許諾の写しを受け取っているはずです。そうでない場合は、Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA * へ手紙を書いてください。\n\n");
        printf("* 【注意】 現在、このバージョン2の発行者(FSF)住所は、正式に新しい住所の 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA に変わっている。\n\n");




----------------------- < Readmeの作成 > -----------------------

次にReadmeの作成です。Readmeとはいわゆる「お読みください.txt」などの説明書のようなものです。

これには、Readmeファイルの作成支援ソフト「れ~どみ~えじた~」を使用しました。
これは、ウィザードと各種テンプレートを使い、Readmeを簡単に作成してくれるソフトです。


ここでは注意すべき点は少ないですね。

・[再配布]は「GPLに基づく」
・今回は、[必要ランタイム]に「GLUT」を入れました。
・現状では動作環境としてXP、開発環境はVC++ 2005しか試していないので、他の環境での動作、開発では不具合が出るかもしれません。

ぐらいでしょうか。



さて、現在ARToolKitのソースの公開に向けた準備を進めている最中ですが、
そこで避けては通れない問題があります。

GNU General Public License(以下GPL)の問題です。(wikipediaのGPL解説ページ



----- <GPLの大まかな説明> -----

ARToolKitのソースのライセンスは、このGPLになっています。
ここでは、GPLについて簡単な説明しかしないので、詳細については他のHPを参照ください。
また、"説明が間違っている"、とか"説明が足りない"部分もあるかもしれません。ご注意ください。

ということで、GPLを(誤解を恐れず簡単に)説明すると、以下のような内容になります。

「GPL付きのプログラムを変更し、再配布する場合は、必ず変更したソースコードも一緒に配布しなくていけない」



GPLでは、入手したプログラムを個人や社内"のみ"で使用している場合には、何の制限もありません。
また、プログラムを使用して書き出された出力結果についても、ほとんどの場合扱いは自由です。

しかし、その実行ファイルやソースを配布しようとした時には、いくつかの制限がつきます。
その1つが、改変したソースコードも必ず、全て公開しなくてはいけない、というものです。

もし、それらの制限が守れないのであれば、実行ファイルやソースの配布は絶対にできません。


ですが実際に、これらの制限をちゃんと守っている人がどれくらいいるのかは、ちょっと怪しいところです。
企業であれば、GPL違反は"ソースの公開又は配布の停止"という非常に重い罰則になるので、どこもGPLには気をつけているはずです。

しかし、個人で公開しているフリーウェア等の場合、"ソースの公開又は配布の停止だけ"という罰則は非常に軽いです。
しかも、ARToolKitのようなプログラムならまだしも、そのアプリがGPL違反かどうかなんて、実行ファイルだけでは普通分かりません。




という背景はありますが、僕自身は「規則だから」という問題は抜きにしても、GPLをちゃんと守ってソースを公開したいと思います。(まぁ理由は後で

さて長くなりましたが、では実際にARToolKitで作ったプログラムを公開する際に、注意すべきことを書いてみます。



----- <ARToolKitのGPLで、問題になるのは?> -----

・僕がARToolKitのプログラムをダウンロードし、プログラムを変更する 
→ ○問題ない
 公開しなければ、何も問題ありません。

・改変したプログラムを実行、その出力結果をWebに公開する 
→ △内容にもよるが、概ね問題ない
 実行結果で、ソース自体を出力しないのであれば、問題ありません。
 実行結果のみなら、動画を公開しても大丈夫です。

・もし、このプログラムの実行ファイルのみを、Webに公開したら 
→ ×GPL違反
 ソースの公開等の制限を実行するか、その旨の文章を入れないといけない。

・ARToolKitで使われている画像(マーカーパターンなど)を改変、公開 
→ △場合によりけり
 画像データ等がプログラムの一部として判断されるかは微妙です。
 しかしそうだとしても、僕の場合は改変した画像も既に公開されているので、問題はないと思います。(ソースも必ず完全公開しますし



----- <GPLに違反したら?> -----

上にも書いたように、少なくてもARToolKit(GNU GPL Ver2)の場合は、
ライセンスに書かれている制限(「ソースコードを公開する」又は「配布を停止する」、など)以外の罰則はないようです。



----- <実際に配布時に行わなければいけないこと> -----

これに関しては、GPLの日本語訳が分かりやすいです。
重要そうな所を一部、ARToolKitの例で説明しますと。

●ARToolKitを元に作られたプログラムを配布する時は、その変更箇所を全て公開しなくてはいけない。

●その時に、変更した旨とその変更日とを、そのファイル上に書かなくてはいけない。

●プログラム実行時に著作権等の注意事項を出力する。

●GPLのライセンスが書かれたテキスト(COPYING.txt)を、配布ファイルの中にも入れておくこと。
等々があります。詳しくは、上記リンクを参照してください。



----- <GPLはなんのためにあるのか?> -----

といったように、少し面倒なGPLですが、これにはちゃんと理由があります。

GPLの目的とは、「フリーウェアが誰かの手によって独占的に保持されるのを防ぎ、
ソースを共有することによって、フリーウェアを発展させていきましょう」というものです。

この考え方は、クリエイティブ・コモンズにも似ていますね。
コピーレフトというものらしいです。

ということで、僕はARToolKitがもっと発展してほしいと思っているので、GPLを推奨します。



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

何度も書かれているように、なにぶん僕も勉強不足な面があるので、間違ってたり、説明足らずな部分があると思います。
なのでGPLについては、ここを信用しないよう、ご自身でちゃんと調べてください。

また、そういった点があった場合、コメント等に指摘をいただけるとありがたいです。
GPLに関する質問については、答えられないかもしれないです。申し訳ないです。



BGM:エコテロニカ(sansuiさん)
他にもARToolKitを安定化させる要素はいくつかあります。

1.キャリブレーション
2.カメラの設定
3.撮影時の注意
4.その他


1.キャリブレーション
キャリブレーションはカメラの歪み補正値を計算するためのものなので、回数が多いほうが正しい結果が得られます。
また、キャリブレーションパターンの正面からの計測だけでなく、斜めや真横に近い位置からの計測を行ったほうが、安定する気がします。

2.カメラの設定
Webカメラなどでは、明るさやコントラストを調節できるものが多いです。この設定値はカメラ固有のものなので、これが良いという値はありません。
そこで、実際にプログラムを動かしながら、カメラの設定を変更してみてください。
オートフォーカスは切ったほうがいいです。

3.撮影時の注意
パターンの時にも説明しましたが、太陽光など強い光の場合はマーカーにハイライトがあたり、認識がうまくいかなくなるときがあります。蛍光灯の光だけでの撮影をオススメします。
また、カメラを早く動かしたり、手ブレなどにより、マーカーの認識率は極端に悪くなります。カメラはできるだけ固定するのが理想的です。
フレームレートは、やはり大きいほうがモデルの歪みが少ないようです。

4.その他
ARToolKitではマーカーの最大サイズ・最小サイズを決めることができます。ありえないサイズのマーカーは最初から除外する設定にすれば、誤認を防げます。
背景となるステージにはできるだけ物を置かず、白など明るい色の場所を選ぶようにしましょう。
最後に、お金はかかってしまいますが、やはりカメラはできるだけ良いものがいいです。
ちなみに私が使っているWebカメラは、logicoolのQcam Pro for Notebooksです。ノートブックタイプを選んだのは、固定しやすく、小さいので小回りが利くからです。

細かいことですが、マーカーの作成では、パターンの模様以外でも気をつけることがあります。

1.できるだけ大きいマーカーにする
2.カラーパターンを使うときには、プリンターも発色がいいものを使用する
3.厚紙に貼り付けるなど、絵が歪まないようにする
4.mk_patt.exeを実行し、パターンデータを作る際には、実際の撮影環境に近づける



1.できるだけ大きいマーカーにする
マーカーを大きくしたほうが、認識率が上がり、安定性も良くなります。
画面にちゃんと収まる範囲内なら、マーカーは大きいほうがいいです。

2.カラーパターンを使うときには、プリンターも発色がいいものを使用する
安いプリンターなどを使うと、3原色が正しくプリントされない場合があります。またプリンターを持っていない方もいると思います。
僕は、プリンタを持ってはいますが、発色が気になったので、ネットプリントを利用しました。これは、PCからデータをアップロードし、セブンイレブンなどで印刷ができるサービスです。ちょっと印刷代はかかりますが、コンビニのプリンタはそれなりに性能がいいので、時々利用しています。

3.厚紙に貼り付けるなど、絵が歪まないようにする
僕が使っているのは、1mmのイラストレーションボードです。200円ぐらいで東急ハンズなどに売っています。かなり硬く、歪むことはほぼないです。
紙をボードに貼り付けた直後は、本などを重しにして挟んでおきましょう。
ボードをくっつける時には、接がれやすい両面テープなどを使うと便利です。

4.mk_patt.exeを実行し、パターンデータを作る際には、実際の撮影環境に近づける
パターンは光の種類や加減などによって、映り方が変わってしまいます。
できるだけ実際の環境に近い状態でパターンデータを作成したほうが良いと思われます。
太陽光よりも蛍光灯など光のほうが光沢が出にくく、撮影には適しています。

ARToolKitをより安定的なものにするには、プログラムもそうですが、使う道具も考えなければいけません。
その道具の中で重要なものの1つが、マーカーのパターンです。

マーカーの数が少ない場合、その中のパターンはよりシンプルなものの方が認識率が良いです。
シンプルなマーカーは既存のサンプルにも入っています。

pattSample1.gifpattKanji.gif














しかし、マーカーの数が多い場合は、誤認識を避けるために、どうしてもパターンが複雑になってしまいます。
そこで、シンプルさを保ちながら、多くのマーカーを作成する方法として、パターンをカラーにしてみることにしました。
最初に作成したのは、次のようなパターンです。

PattColor02.gifPattColor05.gif














このパターンではマーカー内部を4つに分けて、それぞれの区画に3原色(赤、青、緑)を配置し、その組み合わせでマーカーを区別しています。右下に必ずある黒い区画は、マーカーの方向を決めるためのものです。これだと3×3×3で27通りのパターンを作成することができます。

これを実際に使用すると、以下のようなことがわかりました。
・右下の黒い区画をマーカーの黒枠だと誤認してしまう。
・青が黒に近いので、これもマーカーの黒枠だと間違われることがある。
つまり、マーカー内部に黒に近い四角形があると、誤認の確率が高くなることが判明しました。
この教訓により作成したのが、次のマーカーです。

PattColor12.gifPattColor15_B.gif















なんだか顔みたいですね。
まず、右下の黒い区画を白に変え、次に他の色が四角形にならないように、凹を入れました。あと余計な隙間も一応埋めました。
これで、だいぶ誤認しないようになりましたが、どうせ凹を入れるなら、色によって位置を分けたほうが、個体差が大きくなります。

PattColor22.gifPattColor25_B.gif














今回のパターンでは色によって凹の位置が違います。
というわけで、動画で使われているマーカーはこのパターンになりました。
次は凹をもう少し小さくして、試してみます。


※訂正
パターンの凹を小さくして実験しましたが、どうやらこの凹は要らないようです。
ARToolKitでは黒枠を認識するときに、画像を2値化してます。(パターン認識の時はもちろんカラー画像を使う)
そうなるともう色は関係なく、明るいか暗いかのみの違いになります。
つまり、色の領域が外枠と接してさえいれば、四角形と認識されることはなくなるのです。

PattColor4_10.jpg
PattColor4_12.jpg
















しかし、凹が黒枠の誤認識に効果がなくても、各パターンの誤認識には効果があるかもしれません。
とりあえず、この凹なしのパターンで実験を続けてみて、誤認識の割合を見てみることとします。
「ARToolKitの安定化 その②」は、関係計算時の動作についてです。




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

 今回のプログラムでは、3Dモデルの補完の際に用いる関係値を、事前に計算しなければなりません。
しかし、その計算はほぼ自動で行われます。

○計算時の動作は、大まかに言って以下のようになります。

1.モード切替
    プログラムのモードを、計算用に切り替える

2.マーカーの認識
    画面内のマーカーを認識して、各マーカー座標系からカメラ座標系への変換行列を求める(ここまでは今までと同じ)

3.マーカー間の関係を計算
    マーカーが複数見つかった場合は、それぞれの変換行列を用いて、
その関係行列(マーカーA → マーカーB という座標系変換行列)を計算する。

4.関係の平均値を計算
    これをフレーム毎に行っていき、関係行列の平均値を計算する。

5.計算情報を描画
    平均値のサンプル数や誤差も計算し、この情報を画面に描画して、計算の頃合をユーザーに知らせる。

6.他のマーカーに移る
    ユーザーはこの情報を見て計算が大体終わったことを知り、次のマーカーの処理に移ります。

7.全部終わったら、モードを戻す
    上記の処理を、「同時に表示できるすべてのマーカー」に対して行えば、基本計算は終了です。確認モードに戻して、ちゃんと計算できているかをチェックします。

8.全体の再計算
    全体的に上手くいっていない場合は、すべての数値をリセットして、再計算を行います。

9.個々のデータのみ再計算
    いくつかのマーカーのみが上手くいっていない場合は、該当のマーカーのみをリセットして、再計算することもできます。

10.データの保存
    最後に、このようにして作成したデータを保存し、再起動時や他のプログラムで使用できるようにします。


以上が、関係値計算時の大まかな処理です。


順番が逆になってしまいましたが、動画で紹介した内容を書きます。

最初に、ARToolKitについてまったく知らない方は、youtube等で作品を検索してみるのが一番早いかと思います。
AR(augmented reality)(拡張現実)とはVR(virtual reality)(仮想現実)に近い言葉です。
VRが現実に存在しない仮想空間をメインにするのに対し、ARは現実世界がメインで、そこに対して情報を付加したりします。

ARToolKitはそんなARの技術の1つを、なんとフリーで公開しています。なので、研究レベルのアプリを個人でも作成できてしまうというすばらしいツールなのです。

現在、ネット上の動画サイトで、このツールを使った作品が多数製作されています。

さらに、ARToolKitのプログラムに興味がある方がこちらをご覧ください。
工学ナビ:「攻殻機動隊」「電脳コイル」の世界を実現! - ARToolKitを使った拡張現実感プログラミング


さて、僕が作成したプログラムも、そんなARToolKitを使い、作成したものです。




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

このプログラムは、複数のマーカー間の関係を検出して、その関係を用いて3Dモデルの表示を安定化させるためのものです。

そんなすばらしいARToolKitですが、プログラムには欠点もあります。その1つが、「3Dモデルが消えやすい」というものです。モデルは以下の条件で、簡単に消えてしまいます。
    ・黒い枠を認識できなかったとき
    ・内部のマーカーを認識できないとき
    ・マーカーが画面の外に出たとき
    ・マーカーを裏返したとき
    ・カメラを少し早く動かしたとき

最後の、「カメラを早く動かしたとき」という問題は、カメラの性能やマシンスペックが原因の場合が多いので、ここでは無視しました。

この問題を解決する手段として、MultiMarkerというプログラムがARToolKitに入っています。
しかし、MultiMarkerではマーカー間の関係を自分で定義しなくてはいけません。また、復元できる座標系も1つだけです。

ちなみに、その関係をあらわすデータは以下のようなものです。

#the number of patterns to be recognized
3

#marker 1
Data/multi/patt.a
40.0
0.0 0.0
1.0000 0.0000 0.0000 0.0000
0.0000 1.0000 0.0000 0.0000
0.0000 0.0000 1.0000 0.0000

#marker 2
Data/multi/patt.b
40.0
0.0 0.0
1.0000 0.0000 0.0000  100.0000
0.0000 1.0000 0.0000    0.0000
0.0000 0.0000 1.0000    0.0000

#marker 3
Data/multi/patt.c
40.0
0.0 0.0
1.0000 0.0000 0.0000  200.0000
0.0000 1.0000 0.0000    0.0000
0.0000 0.0000 1.0000    0.0000

marker 1をベースとして、marker 2、marker 3にはmarker 1との関係(座標系の変換行列)が書かれています。
単純なマーカーの配置なら、このように簡単な数値になりますが、ちょっとでも配置をずらすと、数値は急に複雑になります。

そこで、僕の作ったプログラムでは、この数値を自動計算します。
そうすることにより、もっと自由に複数のマーカーを配置して、モデル表示の高い安定性が保てるようになる、という訳です。


ARToolKitの開発を始めました

|

最近、全然日記を更新しなかったんですが、せっせとARToolKitでの開発を行っていました。

とりあえずzoomeに投稿してみたので、興味がある方はどうぞ。

ARToolKitの安定化 その①