さて秋も深まり一層寒くなってきました。 これだけ寒いと、運動したくなるという事で、Kinectを使って運動しましょう。
【送料無料】Kinect スポーツ |
運動と言えば、なでしこジャパンなど、サッカー。 拡張現実を使って、サッカーフィールドを再現してみるとか思うのも一つかと思います。
さて、今回は Kinect for Windows SDK beta を題材です。いままでは OpenNI でしたが やっぱり マイクロソフトさんということで、Kinect for Windows SDK beta に取り組みます。
Kinect for Windows SDK beta に関しては、記事を書いているので Kinect for Windows SDK(ベータ版)開発入門 を参考にしてください。
床面について
さて、アバターをだして、サッカーをするのはいいんだけど、奥行きや骨格情報は 先ほどの記事から大体わかる。しかし、床面を推定するとなると、厄介だとおもう。
Kinect for Windows SDK beta は Floor Determinationをする為のパラメータがあり それを取得すると簡単にできそうと考えました。
Programming Guide: Getting Started with the Kinect for Windows SDK Beta
によれば、以下の方程式が成り立てば、そこは床面と推定できるようで、それをつかいます。
The general plane equation is:
Ax + By + Cz + D = 0
where:
A = vFloorClipPlane.x
B = vFloorClipPlane.y
C = vFloorClipPlane.z
D = vFloorClipPlane.w
つまり、ベクトル(x,y,z) と FloorClipPlane(x,y,z) の 内積が -D であれば そのベクトル(x,y,z)は床面と断定できると。
式の変形
「Ax + By + Cz + D = 0」から、床面ベクトル(x,y,z)を求める事を考えると... 例えば次のような事が考えられる。
例えば、人間の頭部分、つまり JointID.Head にある床面がどこか? というと、頭のあるベクトルの X,Zを元にしたベクトルと、FloorClipPlaneの 内積が -D になるような場所を探せばOK。
つまり
「 y = -(Ax + Cz + D) / ( B ) 」
x: data[JointID.Head].Position.X
z: data[JointID.Head].Position.Z
で計算出来るハズと考えた。
//Joint data via e.SkeletonFrame.Skeltons var x = data[JointID.Head].Position.X var z = data[JointID.Head].Position.Z var y = -(FloorClipPlane.X * x + FloorClipPlane.Z * z + FloorClipPlane.W) / FloorClipPlane.Y;
つまり上記で、床面ベクトルが分かるハズと。
ちなみに、上記床面ベクトルは、骨格情報の座標系なので、画像への対応が必要です。
よって以下の方法で、画像空間へマッピングします。
var v = new Vector(); v.X = (float)x; v.Y = (float)y; v.Z = (float)z; float depthX, depthY; nui.SkeletonEngine.SkeletonToDepthImage(v, out depthX, out depthY); depthX = Math.Max(0, Math.Min(depthX * 320, 320)); //convert to 320, 240 space depthY = Math.Max(0, Math.Min(depthY * 240, 240)); //convert to 320, 240 space int colorX, colorY; ImageViewArea iv = new ImageViewArea(); nui.NuiCamera.GetColorPixelCoordinatesFromDepthPixel(ImageResolution.Resolution640x480, iv, (int)depthX, (int)depthY, (short)0, out colorX, out colorY); var p = new Point((int)(pictureBox2.Image.Width * colorX / 640.0), (int)(pictureBox2.Image.Height * colorY / 480));
例えば、上記で pictureBox2 に表示されている画像に表示されている人の頭の直下にある床面座標が とれるでしょう。
試しに上記座標に点を表示してみると、確かに頭の下の床面部分に点が表示されます。
まとめ
FloorClipPlaneがあるので、床面の推定ができます。ただ、画像上の任意の点が床面かどうかを どのように推定すべきかは、一工夫必要そうです。
【送料無料】Xbox360 Kinect センサー |


コメントする