65.9K
CodeProject 正在变化。 阅读更多。
Home

Kinect – 计算器 – 调整骨骼运动至鼠标

starIconstarIconstarIconstarIconstarIcon

5.00/5 (4投票s)

2011年7月22日

Ms-PL

2分钟阅读

viewsIcon

18747

Kinect – 计算器 – 调整骨骼运动至鼠标

在我的上一篇博文中,Kinect – 创建按钮,我展示了一种为 Windows 创建 Kinect 按钮的方法。在接下来的博文中,我将展示更多通过移动 Windows 鼠标光标基于 Kinect 骨骼右手的姿势来实现的方法。

为什么要创建 Kinect 按钮?

为什么不使用 Windows 鼠标光标,并创建出色的手势或头部运动(Smile)来模拟点击,这样我们就无需创建专门的 Kinect 按钮了呢?

答案

  1. 你至少需要站在离电脑屏幕 1 米的距离之外,即使这样,我年纪大了,也无法从那么远的距离清晰地看到…
  2. Kinect 的精确度仍然不够完美,并且从那么远的距离点击一个 48x48 的按钮是很困难的。
  3. 即使你增加了桌面分辨率,用双手同时操作点击仍然不简单也不实用。
  4. 但是,我仍然要这样做!放大镜、酷炫的头部或手势运动等等。

在这篇博文中,我将把那些 Kinect 按钮(基于计时器工作)实现到一个我构建的简单的计算器上,并将 Windows 鼠标钩接到骨骼运动上。

其中唯一的主要问题是将骨骼位置调整到你的屏幕分辨率,正如你所知,骨骼坐标以为单位表示,并且来自 640x480 的屏幕,所以我创建了一个名为 Positions 的新类来帮助我完成这项工作。

AdjustToScreen 方法获取关节(并基于当前的屏幕分辨率),另一个方法获取关节和特定的屏幕宽度和高度。

public static class Positions
{
    //For - Resolution640x480
    private const float SkeletonMaxX = 0.6f;

    private const float SkeletonMaxY = 0.4f;
 

    private static float Adjust(int primaryScreenResolution, 
        float maxJointPosition, float jointPosition)
    {
        var value = (((((float)primaryScreenResolution) / maxJointPosition) / 2f) * 
            jointPosition) 
            + (primaryScreenResolution / 2);
            
        if (value > primaryScreenResolution || value < 0f) return 0f;
 
        return value;
    } 

    /// <summary>
    /// Get the current Joint position and Adjust the Skeleton 
    /// joint position to the current Screen resolution.
    /// </summary>
    /// <param name="joint">Joint to Adjust</param>

    /// <returns></returns>
    public static Vector AdjustToScreen(Joint joint)

    {
        var newVector = new Vector
        {
            X = Adjust((int)SystemParameters.PrimaryScreenWidth, 
            SkeletonMaxX, joint.Position.X),

            Y = Adjust((int)SystemParameters.PrimaryScreenHeight, 
            SkeletonMaxY, -joint.Position.Y),
            Z = joint.Position.Z,

            W = joint.Position.W
        };
 
        return newVector;
    }
    /// <summary>
    /// Get the current Joint position and Adjust the Skeleton joint
    /// position to a specific Screen Size.
    /// </summary>

    /// <param name="joint">Joint to Adjust</param>
    /// <param name="screenWidth">Screen Width</param>

    /// <param name="screenHeight">Screen Height</param>
    /// <returns></returns>

    public static Vector AdjustToScreen(Joint joint, int screenWidth, int screenHeight)
    {
        var newVector = new Vector
        {
            X = Adjust(screenWidth, SkeletonMaxX, joint.Position.X),
            Y = Adjust(screenHeight, SkeletonMaxY, -joint.Position.Y),

            Z = joint.Position.Z,
            W = joint.Position.W
        }; 

        return newVector;
    }
}

现在我创建了另一个辅助类,名为 – NativeMethods,用于根据骨骼关节位置移动和设置鼠标光标位置。

public static class NativeMethods
{
    public partial class MouseOperations
    {
        [DllImport("user32.dll")]
        public static extern bool SetCursorPos(int x, int y);
 
        [DllImport("user32.dll")]

        public static extern bool GetCursorPos(out Point pt);
    }
}

SkeletonFrameReady 中,我添加了另一个质量检查,还检查了关节的 TrakingState,而不仅仅是数据的 TrakingState,并且确保关节位置质量(W)足够高,然后再移动鼠标。

质量检查将防止鼠标跳动。

void SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
{
    foreach (SkeletonData data in e.SkeletonFrame.Skeletons)
    {
        //Tracked that defines whether a skeleton is 'tracked' or not. 
        //The untracked skeletons only give their position. 
        if (data.TrackingState != SkeletonTrackingState.Tracked) continue;
 
        //Each joint has a Position property that is defined by a Vector4: (x, y, z, w). 

        //The first three attributes define the position in camera space.
        //The last attribute (w)
        //gives the quality level (between 0 and 1) of the 

        foreach (Joint joint in data.Joints)
        {
            switch (joint.ID)
            {
                case JointID.HandRight:
                    if (joint.Position.W < 0.6f || joint.TrackingState != 
                        JointTrackingState.Tracked) return;// Quality check 

                    //Based on Skeleton Right Hand Position adjust the location
                    //to the screen

                    var newPos = Positions.AdjustToScreen(joint);
                    if (newPos.X == 0f || newPos.Y == 0f) return;

                    NativeMethods.MouseOperations.SetCursorPos(
                        Convert.ToInt32(newPos.X), Convert.ToInt32(newPos.Y));

                    break;
            }
        }
    }
}

确保你启用了 TransformSmooth你不想让鼠标跳动。(Kinect–如何使用 TransformSmoothParameters 应用平滑帧显示)。

_kinectNui.SkeletonEngine.TransformSmooth = true;
var parameters = new TransformSmoothParameters
{
    Smoothing = 1.0f,

    Correction = 0.1f,
    Prediction = 0.1f,

    JitterRadius = 0.05f,
    MaxDeviationRadius = 0.05f
};
_kinectNui.SkeletonEngine.SmoothParameters = parameters;

实时演示

演示项目

这个项目包含一个 Common 类,其中包含本博文的主要方法,例如移动鼠标和将 Kinect 骨骼调整到桌面分辨率。

尽情享用!

© . All rights reserved.