Kinect 开发 —— 全息图

Kinect的另一个有趣的应用是伪全息图(pseudo-hologram)。3D图像可以根据人物在Kinect前面的各种位置进行倾斜和移动。如果方法够好,可以营造出3D控件中3D图像的效果,这样可以用来进行三维展示。因为WPF具有3D矢量绘图的功能。所以这一点使用WPF和Kinect比较容易实现。下图显示了一个可以根据观察者位置进行旋转和缩放的3D立方体。但是,只有一个观察者时才能运行。

使用Kinect SDK实现这一效果非常简单。Kinect已经在骨骼数据中提供了坐标点的以米为单位的X,Y和Z的值。比较困难的部分是,如何使用XAML创建一个3D矢量模型。在本例子中,我使用Blender这个工具,他是一个开源的3D模型建造工具,可以在www.blender.org网站上下载到。但是,要将3D网格曲面导出为XAML,需要为Blender安装一个插件。我使用的Blender版本是2.6,本身有这么一个功能,虽然有些限制。Dan Lehenbauer在CodePlex上也有针对Blender开发的导出Xmal的插件,但是只能在老版本的Blender上使用。

     WPF中3D矢量图像的核心概念是Viewport3D对象。Viewport3D对象可以被认为是一个3D空间,在这个空间内,我们可以放置对象,光源和照相机。为了演示一个3D效果,我们创建一个新的名为KinectHologram项目,并添加对Microsoft.Kinect.dll的引用。在MainWindow的UI界面中,在root Grid对象下面创建一个新的ViewPort3D元素。下面的代码显示了一个立方体的代码。代码中唯一和Kinect进行交互的是Viewport3D照相机对象。因此很有必要对照相机对象进行命名。

<Viewport3D>
    <Viewport3D.Camera>
        <PerspectiveCamera x:Name="camera" Position="-40,160,100" LookDirection="40,-160,-100" 
                    UpDirection="0,1,0"  />
    </Viewport3D.Camera>
    <ModelVisual3D x:Name="mainBox">
        <ModelVisual3D.Transform>
            <Transform3DGroup>
                <TranslateTransform3D>
                    <TranslateTransform3D.OffsetY>10</TranslateTransform3D.OffsetY>
                </TranslateTransform3D>
                <ScaleTransform3D>
                    <ScaleTransform3D.ScaleZ>3</ScaleTransform3D.ScaleZ>
            </ScaleTransform3D>
            </Transform3DGroup>
        </ModelVisual3D.Transform>
        <ModelVisual3D.Content>
            <Model3DGroup>
                <DirectionalLight Color="White" Direction="-1,-1,-3" />
                <GeometryModel3D >
                    <GeometryModel3D.Geometry>
                        <MeshGeometry3D
                            Positions="1.000000,1.000000,-1.000000 1.000000,-1.000000,-1.000000 -1.000000,-1.000000,-1.000000 -1.000000,1.000000,-1.000000 1.000000,0.999999,1.000000 -1.000000,1.000000,1.000000 -1.000000,-1.000000,1.000000 0.999999,-1.000001,1.000000 1.000000,1.000000,-1.000000 1.000000,0.999999,1.000000 0.999999,-1.000001,1.000000 1.000000,-1.000000,-1.000000 1.000000,-1.000000,-1.000000 0.999999,-1.000001,1.000000 -1.000000,-1.000000,1.000000 -1.000000,-1.000000,-1.000000 -1.000000,-1.000000,-1.000000 -1.000000,-1.000000,1.000000 -1.000000,1.000000,1.000000 -1.000000,1.000000,-1.000000 1.000000,0.999999,1.000000 1.000000,1.000000,-1.000000 -1.000000,1.000000,-1.000000 -1.000000,1.000000,1.000000"
                            TriangleIndices="0,1,3 1,2,3 4,5,7 5,6,7 8,9,11 9,10,11 12,13,15 13,14,15 16,17,19 17,18,19 20,21,23 21,22,23"
                            Normals="0.000000,0.000000,-1.000000 0.000000,0.000000,-1.000000 0.000000,0.000000,-1.000000 0.000000,0.000000,-1.000000 0.000000,-0.000000,1.000000 0.000000,-0.000000,1.000000 0.000000,-0.000000,1.000000 0.000000,-0.000000,1.000000 1.000000,-0.000000,0.000000 1.000000,-0.000000,0.000000 1.000000,-0.000000,0.000000 1.000000,-0.000000,0.000000 -0.000000,-1.000000,-0.000000 -0.000000,-1.000000,-0.000000 -0.000000,-1.000000,-0.000000 -0.000000,-1.000000,-0.000000 -1.000000,0.000000,-0.000000 -1.000000,0.000000,-0.000000 -1.000000,0.000000,-0.000000 -1.000000,0.000000,-0.000000 0.000000,1.000000,0.000000 0.000000,1.000000,0.000000 0.000000,1.000000,0.000000 0.000000,1.000000,0.000000"/>
                    </GeometryModel3D.Geometry>
                    <GeometryModel3D.Material>
                        <DiffuseMaterial Brush="blue"/>
                    </GeometryModel3D.Material>

                </GeometryModel3D>
                <Model3DGroup.Transform>
                    <Transform3DGroup>
                        <Transform3DGroup.Children>
                            <TranslateTransform3D OffsetX="0" OffsetY="0" OffsetZ="0.0935395359992981"/>
                            <ScaleTransform3D ScaleX="12.5608325004577637" ScaleY="12.5608322620391846" ScaleZ="12.5608325004577637"/>
                        </Transform3DGroup.Children>
                    </Transform3DGroup>
                </Model3DGroup.Transform>
            </Model3DGroup>
        </ModelVisual3D.Content>
    </ModelVisual3D>
  </Viewport3D>

上面的代码中,照相机对象(camera)有一个以X,Y,Z表示的位置属性。X从左至右增加。Y从下往上增加。Z随着屏幕所在平面,向靠近用户的方向增加。该对象还有一个观看方向,该方向和位置相反。在这里我们告诉照相机往后面的0,0,0坐标点看。最后,UpDirection表示照相机的朝向,在本例中,照相机向上朝向Y轴方向。

    立方体使用一系列8个位置的值来绘制,每一个点都是三维坐标点。然后通过这些点绘制三角形切片来形成立方体的表面。在这之上我们添加一个Material对象然后将其颜色改为蓝色。然后给一个缩放变形使这个立方体看起来大一点。最后我们给这个立方体一些定向光源来产生一些3D的效果。

    在后台代码中,我们只需要配置KienctSensor对象来支持骨骼追踪,如下代码所示。彩色影像和深度值影像在该项目中不需要用到。


KinectSensor _kinectSensor;
public MainWindow()
{
    InitializeComponent();
    this.Unloaded += delegate
    {
        _kinectSensor.DepthStream.Disable();
        _kinectSensor.SkeletonStream.Disable();
    };

    this.Loaded += delegate
    {
        _kinectSensor = KinectSensor.KinectSensors[0];
        _kinectSensor.SkeletonFrameReady += SkeletonFrameReady;
        _kinectSensor.DepthFrameReady += DepthFrameReady;
        _kinectSensor.SkeletonStream.Enable();
        _kinectSensor.DepthStream.Enable();
        _kinectSensor.Start();
    };
}

为了能够产生全息图的效果,我们将会围绕立方体来移动照相机的位置,而不是对立方体本身进行旋转。首先我们需要确定Kinect中是否有用户正在处于追踪状态。如果有一个,我们就忽略其他的。我们获取追踪到的骨骼数据并提取X,Y,Z坐标信息。因为Kinect提供的位置信息的单位是米,而我们的3D立方体不是的,所以需要将这些位置点信息进行一定的转换才能够产生3D效果。基于这些位置坐标,我们大概以正在追中的骨骼为中心来移动照相机。我们也用这些坐标,并将这些坐标翻转,使得照相机能够连续的指向0,0,0这个原点。

void SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
{
    float x=0, y=0, z = 0;
    //get angle of skeleton
    using (var frame = e.OpenSkeletonFrame())
    {
        if (frame == null || frame.SkeletonArrayLength == 0)
            return;

        var skeletons = new Skeleton[frame.SkeletonArrayLength];
        frame.CopySkeletonDataTo(skeletons);
        for (int s = 0; s < skeletons.Length; s++)
        {
            if (skeletons[s].TrackingState == SkeletonTrackingState.Tracked)
            {
                border.BorderBrush = new SolidColorBrush(Colors.Red);
                var skeleton = skeletons[s];
                x = skeleton.Position.X * 60;
                z = skeleton.Position.Z * 120;
                y = skeleton.Position.Y;
                break;
            }
            else
            {
                border.BorderBrush = new SolidColorBrush(Colors.Black);
            }

        }
    }
    if (Math.Abs(x) > 0)
    {
        camera.Position = new System.Windows.Media.Media3D.Point3D(x, y , z);
        camera.LookDirection = new System.Windows.Media.Media3D.Vector3D(-x, -y , -z);
    }
}

有意思的是,这样产生全息图影像的效果比许多复杂的3D对象产生的全息图要好。3D立方体可以很容易的转换为矩形,如下图所示,只需要简单的将立方体在Z方向上进行拉伸即可。这个矩形朝向游戏者拉伸。我们可以简单的将立方体的UI这部分代码复制,然后创建一个新的modelVisual3D对象来产生新的矩形。使用变换来将这些矩形放X,Y轴上的不同位置,并给予不同的颜色。因为照相机是后台代码唯一需要关注的对象,在前台添加一个矩形对象及变换并不会影响代码的运行。

hologramew


与Kinect相关的一些类库和工具在以后的几年,估计会更加多和Kienct SDK一起工作。当然,最重要的使人着迷的类库及工具有FAAST,Utility3D以及Microsoft Robotics Developer Studio。

    FAAST(Flexible Action and Articulated Skeleton Toolkit)是一个中间件类库用来连接Kinect的手势交互界面和传统的人际交互界面。这个类库由南加利福利亚大学的创新技术研究院编写和维护。最初FAAST是使用OpenNI结合Kinect来编写的一个手势识别类库。这个类库真正优秀的地方在于它能够将大多数内建手势映射到其他API中,甚至能够将手势映射到键盘点击中来。这使得一些Kinect技术爱好者(hacker)能够使用这一工具来使用Kinect玩一些视频游戏,包括一些例如《使命召唤》(Call of Duty)的第一人称射击游戏,以及一些像《第二人生》(Second Life)和《魔兽世界》(World of Warcraft)这样的网络游戏。目前FAAST只有针对OpenNI版本,但是据最新的消息,FAAST现在正在针对KienctSDK进行开发,可以在其官网http://projects.ict.usc.edu/mxr/faast了解更多的相关信息。

    Utility3D是一个工具,能够使得传统开发3D游戏的复杂工作变得相对简单,他有免费版和专业版之分。使用Uitltiy3D编写的游戏能够轻松的跨多种平台,包括web,windows,ios, iPhone,ipad,Android,Xbox,Playstation以及Wii。它也支持第三方插件,包括一些为Kinect开发的插件,使得开发者能够使用Kinect作为传感器来作为Windows游戏的输入设备。可以在Unity3D的官网查看更多信息http://unity3d.com

    Microsoft Robotics Developer Studio是微软针对机器人的开发平台,其最新发布的RDS4.0版本也集成了Kinect传感器。除了能够访问Kinect提供的功能,Kinect也支持一系列特定的基于Kinect的机器人平台,他们可以利用Kinect传感器进行障碍物避让。更多的有关Microsoft Robotics Developer Studio的信息可以访问http://www.microsoft.com/robotics

原文地址:https://www.cnblogs.com/sprint1989/p/3860524.html