Kinect (読み:キネクト)をご存知でしょうか?
このサイトでも Kinect の紹介を行いました。
世間一般の認識では「体感コントローラ」の一種になるのかな。
体感コントローラとは、体を動かしてゲームをするコントローラのこと。
日本で有名なのは Wiiリモコン と
か Playstation Move です。
一時期ニュースでやっていた、うっかり投げつけてテレビ画面を破壊するアレ。
でも、これらと Kinect を一緒にして欲しくはないんですよね。
(使われている技術のレベルが違います。まぁ、比べる事自体無意味ですが…)
その Kinect は一体どんな原理で動作しているのでしょうか?…ということで
Kinect の計測原理について紹介されている次のページをご覧ください。
(自分もこれと同じようなことを書こうとしていたので大変助かりました。)
ランダムドットパターンとか、相互相関とかちょっぴり理系の方むけの内容ですが
要はカメラから投影した光が画像のどのあたりに映っているのか見つけ出し、三角測量の原理で距離を求めています。
この対応を取るテクニックを一般の方が理解するのは、ちょっと難しいかもしれません。
しかし、対応をとった後の三角測量の原理は、測量法として紀元前から存在していますし
ちょっと考えれば誰でも計測原理の大枠を理解できることでしょう。
そんな Kinect を PC に繋いで、距離画像(色が深度情報の画像)を取得できるようになって一年半が経ちました。
累計1000万台以上売れていて、今なお世界中で様々な遊び方が公開されています。
今回紹介する「KinectFusion」はその遊び…失礼、研究の中で大変面白いものです。
Kinect のすごさをもっと広めたいという意思から、一般の方にもわかりやすく紹介しようと思います。
ここから本題に入ります。
コレ↓です。
Microsoft Research - KinectFusion Project Page
論文の pdf ファイルは、ページ右側の Publications から入手できます。
読んで理解できる方は以下の紹介を読む必要はありません。
結構難しいですよ。
たとえ英語が読めても、Iterative Closest Point (ICP) algorithm とか
Volumetric Surface Representation とか、Simultaneous Localization and Mapping (SLAM)とか
この辺の単語の知識がないと、何のことなのかさっぱりわからない構成になっています。
一般の方が原理を理解できるように、簡単に説明します。
Kinect で次に示すようなシーンを計測したとします。
計測風景(左手に持っているのが Kinect です。)
この状態で Kinect から入手できるデータは次に示すような3次元の点群( Point Cloud )です。
(画像は kinect_viewer_cuda という、計測データをリアルタイムで表示できるプロジェクトの実行結果から持って来ました。)
下から見た点群データ
ほぼ正面から見た点群データ
上から見た点群データ
Kinect は一秒間に 30 枚の速度で上で示した3次元の点群のデータを取得できます。
KinectFusion は、この一枚一枚の点群データを位置合わせするところから始まります。
3次元の点群データの位置合わせ、この手の研究に関わる者はレジストレーション(Registration)と言っていますが
このレジストレーションのイメージを次に示します。
見ての通りタマゴのパックです。これを3次元の点群データと見立ててください。
カポッとピッタリ重なるように位置合わせを行います。
これがレジストレーションです。
3次元の点群のデータさえあれば、この問題は解けます。
どうやって解くのかですが、今(2012年)から20年も昔に発表された論文↓に書いてあります。
A Method for Registration of 3-D Shapes.
英語読みたくない、面倒くさい、でも知りたいという方は Iterative Closest Point (ICP) algorithm で調べてみてください。
この ICP アルゴリズムは理系であれば分野を問わず色んな方が勉強されていますので
きっと理解しやすい日本語資料を入手できるでしょう。
さて、レジストレーションした後に、重なる2つの点群データがあるわけですが…
こんなことを一秒間に30回も繰り返していたらあっという間に点の数が膨大になります。
パソコンの記憶容量にも限界というものがあるので、歯止めとなる工夫を施す必要があります。
そこで、空間を格子状に切って、その空間内で頂点の数を一つとする
ボクセル( voxel )で解決しようという発想に至るわけです。(まぁ誰でも考えることです。)
しかし、そんな単純な考えだけではなく、今回のような点群データから
複雑なモデルを構築することを視野に入れた研究が行われました。
すみません、自分はあまり詳しくないのですが論文↓を紹介します。
A Volumetric Method for Building Complex Models from Range Images
Range Image は距離画像のことです。
目を通せばボクセルを使って距離画像からモデルを構築するという大まかな流れはつかめるでしょう。
とにかくこれで、レジストレーション後の点群データを使って統合モデルの構築を行うことができます。
最後に重要なのが、上記の処理を GPU で処理するようにして高速化したということです。
CUDA で調べれば、およそ何のことなのか理解できるでしょう。
並列演算でリアルタイム処理できるようになったということです。
まとめます。
Kinect の距離画像を一枚一枚レジストレーションして
ボクセルを使って統合モデルを構築する。
また、これをリアルタイムで処理する。
以上が KinectFusion です。
原理を簡単に理解した上で紹介動画を見てみましょう。
KinectFusion 紹介動画
動画のキャプチャ1:計測風景
動画のキャプチャ2:右下に注目、統合モデルの構築中
動画のキャプチャ3:右下に注目、統合モデルが正しく構築できています。
***おまけ***
KinectFusion がうまく動作しないケースがあることを知ってほしいです。
例えば平たい壁一面を計測している時です。
タマゴのパックのように凸凹していればピッタリ一致する姿勢が一つ求められるのですが
平面の場合、ピッタリ重なる姿勢は無数に存在するので、間違ってレジストレーションすることがあります。
まぁ、そういう時はカラー画像を使えば良いのですが…処理速度の問題で実現は不可能です。(2012年現在は)
オフラインで、ですが次の論文で平面の距離画像をレジストレーションして統合モデルの構築ができることを示しています。
100Hzテクスチャ付き距離画像計測システムの構築と三次元マッピングへの応用
伝えたかったのはリアルタイム処理で行うということが大変難しいということです。
オフラインだったら KinectFusion でやっているようなことは、ずっと以前から研究されてきました。(尽くされたと言っていい)
学生が容易く実現できるくらいですし、今時オフラインで統合モデルを構築したところで新規性をアピールするのは難しいです。
一面同色で印となるようなものがまったくない状況ではどうなるかですか?
(学会とかで、無知な学生がよくこんな質問しているのを見かけます。)
その問題は視覚情報だけでは解けません。カメラだけではどうしようもないことです。
解くことは不可能です。(人間のように視覚以外に速度、加速度センサでもあれば別ですが…)
ここまで紹介してきた KinectFusion ですが、研究成果を傍から眺めるだけではなく
ソースコードを入手、ビルド、実行することで、なんとKinectFusion を手元で試すことができるのです。
KinectFusion のクローンプロジェクト Kinfu のビルド方法を紹介します。
…といっても、その方法は次のページにて懇切丁寧に示されています。
(ここで紹介されている手順を踏めば誰でも KinectFusion をビルドできるでしょう。)
まとめ?ブログ OpenNI Advent Calendar 2011/12/21 - KinectFusion -
今から半年ほど古い情報なので、多少違いがあるかもしれません。
そこで、自分がビルドしたときの手順を以下に書き残そうと思います。
PCL/3rdParty のインストール
PCL ソリューションのソースファイルの入手
CUDA ToolKit/SDK のインストール
PCLソリューションの作成、ビルド
の順番で説明します。
***PCL/3rdParty のインストール***
3次元点群処理(3D point cloud processing)のための巨大なオープンプロジェクト
それが Point Cloud Library (PCL)です。
その PCL の 3rdParty をインストールします。
3rdParty とはプロジェクトが利用する外部ライブラリのことです。
C++ の便利機能とかは boost, 数学の便利関数群は Eigen, インタフェースは Qt とか…
これらを一個一個ビルドしてバイナリ(利用できる状態のもの)を用意するのは大変なので
あらかじめビルドしたものを入手しましょう。そういう背景から行う手順になります。
Windows 版は上記リンクから入手します。ご自分の開発環境と一致するものをダウンロードしてください。
自分の環境は VisualStudio 2010 32bit 版なので次の画像の赤枠で示したものをダウンロードしました。
適当なフォルダにインストールしておきます。
これで 3rdParty のインストールは完了です。
***PCL ソリューションのソースファイルの入手***
TorroiseSVNを使って次のリポジトリのURL
http://svn.pointclouds.org/pcl/trunk
からチェックアウトを行います。
TorroiseSVN については以前 Tips で紹介しています。
TorroiseSVN をインストールしていれば、任意のフォルダを右クリックした時に次のメニューが表示されます。
選択するとリポジトリURLを聞いてくるので、先ほどのパスを記入します。
2012/5月中頃に最新のリビジョン(HEAD revision)を引いてみました。
ソースが正しく引ければ、指定したフォルダの下に次のフォルダ構成でファイルが作成されます。
表示しきれていませんが、この画像の下にもたくさんフォルダがあります。
で、画像をよく見るとアイコンに x 印が付いている 3rdParty のフォルダに気づくと思います。
一つ前の手順で PCL/3rdParty をインストールしたと思いますが、これをフォルダごと置き換えます。
自分はバックアップを取る意味合いで、もともとあった 3rdparty フォルダを bk_3rdparty とリネームしています。
(別に削除しても構いませんよ。)
***CUDA ToolKit/SDK のインストール***
ダウンロード、インストール方法は公式ページにわかりやすく示されているので、手順に従ってボタンを押すだけです。
自分は Windows7 64bit マシンで 32bit の開発なので、次の画像の赤枠の部分をクリックして
ダウンロード、インストールを行いました。
CUDA ToolKit/SDK それぞれのルートフォルダを覚えておくこと、これ大事です。
自分は次のパスでした。
C:/Program Files (x86)/NVIDIA GPU Computing Toolkit/CUDA/v4.2
C:/Users/simplestar/AppData/Local/NVIDIA Corporation/NVIDIA GPU Computing SDK 4.2/C
CUDA の準備で問題は起きないでしょう。
***PCLソリューションの作成、ビルド***
まずは次の CMake のサイトから、CMake をダウンロード/インストールしてください。
インストール後はスタートメニューに CMake フォルダがあるので
次に示す cmake-gui の項目を選択してGUIを起動します。
起動直後の様子を次に示します。
TorroiseSVN でチェックアウトした PCL のフォルダに CMakeLists.txt ファイルがあるので
この設定ファイルを、画像で示したGUIウィンドウにドラッグ&ドロップします。
一見パスが記入されるだけで何も変化は見られません。
気にせず Where to build the binaries の項目のパスを
(PCL のチェックアウトフォルダパス)\build
にして、中段の「Configure」ボタンを押してください。
すると次に示すように、開発環境はこれで良いかと聞いてきますので
自分で使っている開発環境を指定してください。
(私の場合は VisualStudio2010 なので Visual Studio 10 です。)
Configure が完了すると、パスの指定が不完全だと次のように赤く示されるハズなので
3rdParty のフォルダから対応するパスを順次記入していってください。
具体的なパスは次の参考ページに示されています。(これで記入に迷うことはないはず)
まとめ?ブログ OpenNI Advent Calendar 2011/12/21 - KinectFusion -
CUDA ToolKit/SDK のパスについては、CUDA ToolKit/SDK のインストールで確認したパスを記入すること
重要なのが Kinfu プロジェクトを作成するには GPU を使用することを念頭に
チェックボックスの状態をオンにしなければならないということです。
たとえば次に示すチェックボックスです。
ひと通りの記入が終わったら Configure を押して、赤くならないことを確認します。
(この操作は人によって失敗するかも、うまくいかない場合は個人で問題を解決するしかない)
問題なければその隣のボタン Generate を押します。
成功すれば指定したパスに PCL.sln ファイルが作成されるはずです。
ではこのソリューションファイルを開いて kinfu_app プロジェクトがあるか確認してみましょう。
(kinfu_app プロジェクトがない場合は、設定を見なおして Generate し直す必要があります。)
ここまでくれば、kinfu_app をビルドするだけです。
環境に問題がなければビルドに成功します。
kinfu_app プロジェクトをビルドできたものとして説明を続けます。
また、ビルドしていない方も、どんなことができるのかは興味のあるところだと思います。
よろしければお付き合いください。
まずは動作確認をしてみます。
Kinect を PC へ接続します。
(Kinect には for Windows と for XBOX 360 の二種類ありますが、使っているのは for XBOX 360 です。)
for XBOX 306 のドライバなど、接続の話は次のページで説明しています。
PCL.sln を開いて、kinfu_app プロジェクトをスタートアップに設定
F5でビルド実行します。実行画面を次に示します。
ウィンドウは4つ。
左上が View3D from ray tracing(現在GPUが構築している統合モデル)
右上が Kinect Depth stream(距離画像)
左下が Scene Cloud Viewer(CPUでシステムメモリから表示しているキャプチャ結果ビューワ)
右下が標準出力です。
まず左下の Scene Cloud Viewer にフォーカスを当てて 'H' キーを押します。
するとコンソール画面に次のヘルプメッセージが表示されます。(以下の記述は kinfu_app.cpp から拝借)
使い方はここに書かれている以外にも、いくつか隠しコマンドがあります。
ソースを見れば全部書かれています…ということでそのソースのコメントを次に示します。
この程度の英語くらいは誰でも読めますよね、解説は飛ばします。
基本的な使い方がわかったところで、コマンドライン引数の説明をします。
コマンドライン引数の解析を行なっているのは main 関数です。
軽く目を通せば漏れ無く理解できるでしょう。
どんなコマンドライン引数が有効なのかハイライトしてみました。
お気付きの方も多いと思いますが CLI 用のヘルプも用意されています。
コマンドライン実行(cmd.exeから起動)で -h または --help オプションを指定すれば
次のヘルプメッセージが表示されます。
コマンドライン引数の説明も不要ですね、困ったらヘルプメッセージを参照してください。
上記で示したコマンドライン引数を全部試している途中で out of memory メッセージが表示されて
起動に失敗することがありました。
unknown error もあったかな…
修正というほどのことではありませんが、ビデオメモリの使用量を減らすことができないと
いくつか使えない機能が見受けられます。
気になる、ビデオメモリの使用量を減らす方法をご紹介します。
KinectFusion の原理を簡単に理解している方なら、ボクセルの解像度を下げれば
この問題は解決するという説明で納得できると思います。
で、そのボクセルの解像度を決めている箇所が次の列挙型の定義の部分です。
書いてある通り 32 の倍数で解像度は決定しなければなりません。
out of memory, unknown error でお悩みの方はこれを思い切って低い値にしてみると
ひとまず動作するのではないでしょうか?
もう一つ、その下に VOLUME_SIZE が定義されていると思います。
これはボクセルで区切る立方体のスケールです。
小さい値にすれば解像度を上げずとも統合モデルの精度を上げることができます。
変更する場合は kinfu_app.cpp の main 関数のローカル変数 volume_size も
同期して変更する必要があるかと思います。(同期しないといけないという確証はないですが…)
さっそく精度が上がるのか試してみましょう。
どうも VOLUME_X, Y, Z = 512 では、私の環境で mesh を取得しようとすると unknown error が出るようです。
仕方がないので VOLUME_X, Y, Z = 256 に下げて mesh を取得するように修正。
結果を次に示します。
計測対象(デジカメで撮影した写真)
Scene Cloud Viewer
View3D from ray tracing
KinectFusion の使い方で既に紹介しましたが、いつくかの形式で
計測したメッシュデータをファイル出力することができます。
たとえば '7' キーを押すことで Stanford 形式の (.ply) ファイルを出力できます。
嬉しいことに Blender の標準のインポーターに .ply 対応があるので、Blender で読み込んでみました。
(Blender とはフリーで使えるモデリング、アニメーション制作ソフトです。使い方はコチラ)
読み込んだ結果を次に示します。
Blender で読み込んだ結果。
Blender にモデルデータとして読みこませることができたので
ここからはユーザーが好きに利用、加工できます。
実際に存在する空間を忠実に再現したマップ制作など
使い方はアイディア次第ですので、応用の可能性は大きいです。
ちょっと長くなったのでここで本文をまとめます。
KinectFusion についての簡単な説明をしました。
Kinfu というプロジェクトをビルドする方法を示しました。
エラーが起きる場合の対処のための、ソースファイルの修正箇所を示しました。
Kinfu で作成した統合モデルを Blender で表示できることを示しました。
私は KinectFusion を初めて知った時、衝撃を受けました。
この素晴らしい技術をもっと多くの方に知ってもらいたいです!
2012/06/02 初記。
2012/06/03 更新。