Kinect应用中Skeleton、Gesture period有什么用?

What is the use of Skeleton, Gesture period in Kinect application?

我正在编写基于 Kinect 的应用程序。我需要实现向右挥手的手势。我从网上找到一段使用C#的代码片段,但我对这段代码有些疑惑。你能帮帮我吗?

代码:

public class KinectClass
{
    public void KinectInitialize ()
    {
        m_myKinect.Start();
        m_myKinect.SkeletonStream.TrackingMode = SkeletonTrackingMode.Seated;
        m_myKinect.SkeletonFrameReady += m_myKinect_SkeletonFrameReady;
    }

    void m_myKinect_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
    {
        using (SkeletonFrame frame = e.OpenSkeletonFrame())
        {
            if (frame != null)
            {
                if (0 == frame.SkeletonArrayLength) return;
                m_skeletons = new Skeleton[frame.SkeletonArrayLength];
                if (m_skeletons == null) return;
                frame.CopySkeletonDataTo(m_skeletons);
            }
        }

        foreach (Skeleton skeleton in m_skeletons)
        {
            if (skeleton.TrackingState == SkeletonTrackingState.Tracked)
            {
                UpdateSkeletonHistory(skeleton);
                value = gestureobject.Detectgesture();
            }
        }
    }
}

此外,还有一个检查波函数的手势class:

class Gesture
{
    private List<Skeleton> SkeletonHistory;
    private List<Skeleton> localSkeletonHistory;

    public void UpdateSkeletonHistory(Skeleton SkeletonData)
    {
        SkeletonHistory.Add(SkeletonData);

        if (SkeletonHistory.Count > 90)
        {
            SkeletonHistory.RemoveAt(0);
        }

        return ;
    }

    public short Detectgesture()
    {
        short sReturnvalue = -1;
        int gesturePeriod = 2;
        int indexesPerSecond = 30;
        int indexesToCheck = gesturePeriod * indexesPerSecond;
        localSkeletonHistory = new List<Skeleton>(SkeletonHistory);

        if (m_SkeletonHistory.Count > indexesToCheck)
        {
            localSkeletonHistory = new List<Skeleton>(m_SkeletonHistory);

            if( waveright() )
            {
                Console.Writeline("waveright");
            }
        }
    }

    private bool waveright()
    {
        Console.WriteLine("wave right START");
        bool Movedright = false,
        Movedleft = false;

        float refDistance = 0.2F;

        float startPos = localSkeletonHistory[0].Joints[JointType.HandLeft].Position.X;

        for (int i = 0; i < localSkeletonHistory.Count; i++)
        {
            if (!(localSkeletonHistory[i].Joints[JointType.HandLeft].Position.Y <= localSkeletonHistory[i].Joints[JointType.Head].Position.Y))
            {
                break;
            }
            if (localSkeletonHistory[i].Joints[JointType.HandLeft].Position.X >= (startPos + refDistance))
            {
                Movedright = true;
            }
            if (Movedright && Math.Abs(localSkeletonHistory[i].Joints[JointType.HandLeft].Position.X - startPos) <= 0.1 )
            {
                Movedleft = true;
                m_SkeletonHistory.Clear();
                break;
            }
        }

        return Movedleft;
    }
}

我能理解Kinect功能,但我对手势功能一头雾水。我的问题如下:

你需要记住的是,仅仅因为 Hand 的位置是正确的,相对于 body。这并不意味着他们在向右挥手。

A wave right 是向右的过渡。所以你不能通过当前位置来确定。这就是为什么您需要使用 SkeletonHistory 来跟踪之前的位置。

所以算法的直截了当的概述是:

For the previous positions since the last triggered gesture:
     If each Skeleton's Y position is greater than the last, then the person is waving right

当然,一只手会向右移动很多次,并不代表它就是向右挥手。因此,您需要确定手必须向右移动多长时间才能成为真正的向右挥手手势。

refDistance 表示手至少移动了这个距离才能被归类为正确的波浪。

在这里,我相信编码器是在说手势需要持续至少 2 秒。所以如果我们每秒得到 30 个骨架,那么我们需要检查最后 60 个骨架:

int indexesToCheck = gesturePeriod * indexesPerSecond;

msdn 文档实际上对这些东西非常好:

https://msdn.microsoft.com/en-us/library/jj131025.aspx

我发现这本书非常适合入门这些东西:

Programming with the Kinect for Windows Software Development Kit (Developer Reference)