Top > Kinect > KinectForWindowsSDK > Basics > StartUp > DepthDataFormat
Last-modified: Mon, 02 Jul 2012 12:15:58 HADT
Counter:8116 Today:2 Yesterday:0 Online:3
このエントリーをはてなブックマークに追加

深度情報(short[])のデータ構造と各値の取得方法詳細

About

 ここではKinectから送られてくる深度情報(short[])がどういったデータ構造になっているのかを解説して、またそこから実際の深度値やプレイヤ識別値を取得する方法について解説します。

short型に含まれる値は「深度値」と「プレイヤ識別値」の2種類


4.png
深度値のイメージ
3.png
プレイヤ識別値のイメージ

 KinectのIRカメラ(赤外線カメラ)が映しだす各画素に対応する情報はshort型で与えられ、それが解像度分あるために実際にはshort[]として与えられます。1画素分の情報、つまりshortあたりに含まれる値には、2種類の値があります。1つが「深度値」2つ目が「プレイヤ(ユーザ)識別値」です。深度値はその画素に投影される空間までの距離を示す値です。一方でプレイヤ識別値はその画素に何番目に認識されている人物が表示されているか(いないか)を示す値となっています。

 例えばKinectの有効範囲内に2人の人物が映っているとします。ある画素に1人目の人物が映っていれば、その画素(short)が示すプレイヤ識別値は1です。またそれとは異なる画素に2人目の人物が映っていれば、その画素が示すプレイヤ識別値は2となります。2人の何れもが映っていない画素にはプレイヤ識別値が与えらないので0となります。

プレイヤ識別値と深度値の取得

 short型は2byteで表されるデータです。1byte = 8bit ですから、つまりshort型は16bitで表される値です。また1bitとは 0 もしくは 1 で表される値ですから、short型(2byte)は、 0 もしくは 1 が16個並んで表される値ということになります。ここでKinectから与えられるshort型を構成するデータは、全16bit中、13bitが深度値:Dで、残り3bitがプレイヤ識別値:Pです。つまり深度値やプレイヤ識別値を取得したい場合、shortの値を構成する各bitの成分をバラして、それぞれのデータを個別に取得する処理が必要になります。

0.png

プレイヤ識別値の取得

 まずプレイヤ識別値の取得から行います。下のソースコードのようにすることで取得することができます。depthDataArray[i]は、ある画素に対応するshort型の値です。

int playerIndex = depthDataArray[i] & DepthImageFrame.PlayerIndexBitmask;

 この計算を行うと、次の画像の様に処理されることに注意してください。

1.png

 PlayerIndexBitmaskは7です(Kinectの最大識別人数に等しい)。つまり2進数で表すと「111」となります。これを16bitに揃えると「0000000000000111」です。「&」演算子は論理積演算子です。論理積演算子は互いに「1」でなけらば「0」になる演算を行います。つまり画像の様に深度情報が与えられる箇所:Dは常に0を返し、プレイヤ識別情報が与えられる箇所:Pのみ「1」が返る可能性があります。

 Kinectは最大7人を識別することができますから、取得できるプレイヤ識別情報は0~7です。例えばKinectの有効範囲に2人の人物が映っていたとして、得られる値は「0」もしくは「1」か「2」です。ある画素に1人目の人物が映っていれば、図のPに該当する箇所には「001」が入り、論理積演算の結果「001」だけが残ります。これを10進数に直せば「1」です。一方である画素に2人目の人物が映っていれば図のPに該当する箇所には「010」が入り、論理積演算の結果「010」となって10進数で「2」となります。最大取得人数7は2進数で表すと「111」ですから、下位の3bitだけ考慮する様な計算式で全てのパターンを網羅できるというわけです。

深度値の取得

 続いて深度値を取得します。次のソースコードの様にして取得することができます。

int depth = depthDataArray[i] » DepthImageFrame.PlayerIndexBitmaskWidth;
2.png

 深度値を取得する場合には、シフト演算子「>>」を利用します。シフト演算子は「<<」ないし「>>」によって左か右に与えられた数分だけbitをずらします。今回は"右に3ずらす"ので図のように、データを構成する16bitの内、下位の3bit、つまりプレイヤ識別値:Pが捨てられ、左に3bit空いた分には0が入ります。こうすることによって「000DDDDDDDDDDDDD」となり、16bitの中には深度値を構成する13bitの情報のみが残るようになりました。

 ここでプレイヤ識別値の取得時と同じ要領でマスク処理(論理積)による処理を施すと「DDDDDDDDDDDDD000」となります。この2進数を10進数に直す時は、下位の「000」までを考慮した16桁全てが対象となります。深度値は構成される13bit分によって表されるので、10進数とする場合に対象となって欲しい箇所は「000」を除く「DDDDDDDDDDDDD」のみです。よって「000DDDDDDDDDDDDD」とする必要がでてきます。結局はシフト演算によってbit情報を調整するわけですから、論理積処理は深度値取得時には不要となるのです。

捕捉資料

 深度値を10進数に変換する場合、深度値を構成する13bitの内、上位の1bitは無視されます。つまり常に0を返すということです。下位の12bitが仮に全て1を示すとして、その10進数は4095です。Kinectの有効計測範囲は4000mm(=4m)なので実は12bitで十分なわけです。これを利用してビット演算によって値の打ち落としを行う場合もあるので注意してください。

公式には4mって書いてあるけど、DepthStream.TooFarDepthを取ると4095を示す。Kinectの有効計測範囲は正確には4095mmなのかな?