11、kinect
Kinectでのキャプチャ機能を付けました。
OpenNIを使用するのでキャプチャするには下準備としてOpenNIをインストールする必要があります。
OpenNIはバージョンによって動かなかったりする時がたまにあるので
OpenNIで使用するOpenNIのバージョンをzipにしました。
こちらからダウンロードしてください。
なおこのzipに入っているOpenNIのファイルのライセンスについては
http://www.openni.org/
https://github.com/avin2/SensorKinect
をご覧ください。
Kinectでキャプチャするには上のスクリーンショットのように初期姿勢がせんだみつおポーズのモデルを用意します(このポーズは必須)。
(OpenRDBのzipのMedia/KinectSample/hattousinの中にスクリーンショットのデータを同梱しました。)
操作の順番は
kinectメニューの「ライブラリロード」、「kbs読み込み」または「kbs作成」を実行します。
次に初期状態のモーションの長さでは1秒くらいでキャプチャが終了するので
ツールウインドウのプロパティを実行し、モーションの長さを長くします。
モーション長800くらいが安定しています。
あまり長いと処理が重くなるためか、OpenNIの応答が無くなったりして不安定になります。
次にkinectメニューの「キャプチャ開始」を実行します。
実行したらkinectとの距離を2mほど取り、せんだみつおポーズをしてください。
認識されると3Dウインドウ上に自分の赤いシルエットが表示されます。
シルエットが表示されにくい時は、小さく前後に動くとすみやかに認識されます。
3Dモデルが微妙に動いたらキャプチャ開始です。
きれいにキャプチャするにはモーションの演じ手側がキャプチャしにくいポーズを避けるなどの心配りすることが必要です。
ぷるぷる震える現象はkinectメニューの「motion平滑化」を実行すると滑らかになります。
####### 2012/03/14 5:50 プログラム修正。
どんな姿勢のモデルデータでもKinectでモーションキャプチャ出来るようになりました。
キャプチャ前にIKなどでせんだみつおポーズにし、kinect-->初期姿勢設定メニューを実行すると可能になります。
kinectの初期姿勢は現在保存されません。モデルデータを読み直すたびに実行してください。
####### 2012/03/15 7:20 プログラム修正
タイムラインの再生ボタン類の大きさを大きくしました。
ソースは下のページからダウンロードしてください。
OpenRDBダウンロードページ
11−01、OpenNIのインストール
上記のリンクからOpenRDBで使用するOpenNIをダウンロードできます。
昔のバージョンと比べてインストールは簡単になっています。
まず、古いバージョンのOpenNIがインストールされている場合は
全てアンインストールします。
kinectをパソコンに接続します。
openni-win32-1.5.2.23-dev.msiをダブルクリックします。
画面の指示に従い、設定項目はデフォルトのままインストールします。
nite-win32-1.5.2.21-dev.msiをダブルクリックします。
画面の指示に従い、設定項目はデフォルトのままインストールします。
avin2-SensorKinect-faf4994.zipを解凍します。
そしてBinフォルダの中のSensorKinect091-Bin-Win32-v5.1.0.25.msiを実行します。
パソコンを再起動します。
これでインストールは完了です。
注意点は64ビットOSでも32ビット版のプログラムをインストールすることです。
11−02、OpenNIでボーンの位置を取得する
OpenNIの関数を使うプログラムはKinecoDXソリューションにまとめてあります。
OpenNIの関数を使う部分を別DLL、KinecoDX.dllにします。
OpenNIのライセンスはGPLなので
この部分を別DLLにすることで他の部分のライセンスに影響を与えないようにします。
OpenNIのボーンは15個あります。
|
上のようなenumを定義しました。
KinecoDXで全部のボーンの3Dの位置を取得します。
位置の配列はSKEL_MAXの要素数で定義します。
SKEL_TOPOFJOINTはこちらで勝手に付け足したものです。
ですので全部で16個のボーンになります。
OpenNIのおかげでだいぶ簡単に3D座標が取得できます。
KinecoDX.cppを見ればだいたい理解できるでしょう。
ちょっと迷うかもしれないのは
トラッキングの部分です。
OpenNIは初期姿勢としてせんだみつおポーズを要求します。
このポーズを認識するとTrackingFフラグがtrueになり、
ボーン座標の取得が始まります。
TrackingFフラグはDLL外部からはOpenNIIsTracking命令で取得可能です。
トラッキング開始直後はすこし不安定なことがあるので
4回トラッキング成功を認識してからTrackingFフラグをtrueにしています。
11−03、kbsファイル
11-02でKinectのボーンの種類を見ました。
実際のモデルデータとKinectのボーンと名前も構造も完全に一致する場合はいいのですが
多くの場合は実際のモデルデータの方がボーンの数が多いですし
名前も違うと思います。
そこで実際のモデルのボーンとKinectのボーンとの対応表を作成します。
OpenRDBではこの対応表をkbsと呼びます。
kbsとは、KinectBoneSettingの略です。
OpenRDBのkinectメニューのkbs作成を実行すると図11−01のようなダイアログが出ます。
図11−01、kbsダイアログ
図11−01のようにこれでボーンの数や名前の違いなどを吸収します。
階層構造は完全に一致する必要はありませんが
kinectで親の方の階層のものが、実際のモデルで子供の方の階層になっていたりすると
うまく動かないので注意が必要です。
つまり階層の上下関係は満たしていないといけません。
このkbsの設定はCModelのCKbsFile*に格納します。
保存も出来ます。
参考までにkbsの一例を載せておきます。
|
11−04、初期姿勢登録
OpenNIでは初期姿勢がせんだみつおぽーずであることが必須ですが
このポーズでモデリングすると影響度の設定がうまくいかないことがあります。
ですのでモデリングのポーズを自由に出来る工夫をしました。
モデルデータを読み込んだ後に、IKなどでせんだみつおのぽーずにします。
そしてkinectメニューの「初期姿勢登録」を実行します。
登録実行時にせんだみつおポーズにするための各ボーンのクォータニオンを
CBone::m_kinectqに格納します。
モーションキャプチャはせんだみつおの初期ポーズを想定して計算して
最後に実際のモデルにクォータニオンをセットする際に
m_kinectqで回転してからモーションキャプチャのクォータニオンで回転するような
クォータニオンの掛け算をして設定します。
こうすることでどんなポーズでモデリングしても
OpenNIでモーションキャプチャできるようになります。
11−05、kinectモーションキャプチャ
それではいよいよモーションキャプチャのソースを見てみます。
モーションキャプチャのメイン呼び出しはKinectMain.cppにあります。
キャプチャがスタートしたら毎フレームCKinectMain::Updateを呼び出します。
Updateのソースを貼り付けます。
|
冒頭でm_rendercnt % 2が0以外の時にリターンしています。
これはOpenRDBのfpsが60なのに対し、OpenNIのfpsが30なためです。
トラッキングがtrueのときのみボーン位置の計算をします。
ボーンの位置はCRpsに格納します。
rpsとはリアルタイムポジションの略です。
CRpsでは3フレーム分、全ボーンの位置を保持します。
最初のフレーム、フレーム0にはキャプチャを開始してトラッキングがオンになった直後の
ボーンの位置を保存します。
これはせんだみつおポーズの座標で、全ポーズ計算の基準値となります。
最後のフレーム2には最新のボーン位置を格納します。
そして真ん中のフレーム1には1回前の計算時のボーンの位置を格納します。
この座標セットの部分がCRps::SetRpsElemです。
|
上で説明したとおり、3フレーム分のボーン位置の設定をしています。
クォータニオンを計算するだけならフレーム0とフレーム2だけで出来ます。
1回前のポジションを保持する理由はオイラー角の計算のためです。
クォータニオンをオイラー角に直す場合
オイラー角は何通りも考えられます。
これを一意に絞り込むために1回前の姿勢をチェックし、それに一番近いオイラー角を計算します。
CKinectMain::Updateでは位置を設定した後にCalcTraQを呼び出しています。
CalcTraQでボーン位置からボーンのローカルのクォータニオンを計算します。
CRps::CalcTraQのソースを貼り付けます。
|
CTraQクラスでボーン位置からクォータニオンへの変換をします。
この変換はボーンの部位で3種類の計算に分けています。
TorsoはCalcTorso、NeckはCalcNeck、それ以外はCalcQで計算します。
まずはCalcTorsoを見てみます。
|
左右のヒップのベクトルの傾きを計算してそれをクォータニオンにしているだけです。
CalcNeckも貼り付けます。
|
大きく2つの部分に分かれています。
前半はXZ平面での傾きを計算しています。
そして後半は体の前後の傾きを計算しています。
前半はTorsoの計算方法と同じです。
後半でクォータニオンを算出する際にDCalcDiffQを呼んでいます。
これは回転前のベクトルと回転後のベクトルからクォータニオンを計算するものです。
2つのベクトルの外積から回転軸を求め、内積のacosから回転角度を求めて
それらからクォータニオンを計算しているだけです。
CalcQは以下のようになります。
|
Neckの後半部分と同じです。
回転前後のベクトルからクォータニオンを求めています。
長々とtwistflagが0、つまりねじれ防止機能がオンの時のソースが書いてありますが
これはまだ実験段階で実用的ではありません。
最初にRokDeBone2で作ったテストデータでこのねじれ防止がうまく働いたので
残してありますが、どうやらデータ依存の部分が残ってしまったようで
まだまだ汎用ではありません。
今のところ、この部分は無視してしまって構わないです。
CKinectMain::Updateに戻ります。
クォータニオンを計算したらCRps::SetMotionを呼び出して
モデルデータのモーションポイントにセットします。
|
SKEL_TOPOFJOINTにだけ移動成分を設定しています。
この際にモデルのスケールとKinectの座標のスケールを合わせるために
モデルのバウンダリー情報を使って適切な値になるようにスケールします。
オープンソースのトップに戻る
トップページに戻る