【原】使用 Kinect SDK 中手的 Grip/Release 事件

本文参考以下文章:
http://www.cmsoft.com.br/index.php?option=com_content&view=article&id=292:kinect-sdk-17-hand-events&catid=1:latest-news&Itemid=110
http://blog.csdn.net/creategen/article/details/8698821

微软的Kinect SDK在1.7版本中新增了手的抓握事件, 给程序开发增添了新的可能。 微软在Developer Toolkit中提供的例子使用了标准的Kinect控制控件(Kinect.toolkits.controls), 其中滑动列表控件就利用了抓握手势。 但是如果我的程序只需要获取手的状态, 不需要将其应用在界面程序中呢?这就需要我们去研究Kinect控件中的代码了~但是其中的代码非常复杂, 这里给出一个监听手抓握事件的最小C#程序

首先新建工程, 然后向工程中添加引用, 添加如下引用:
Microsoft.Kinect
Microsoft.Kinect.Toolkit
Microsoft.Kinect.Toolkit.Interaction

然后在Form1.cs中的窗口加载事件中加入初始化代码:

            // Look through all sensors and start the first connected one.
            // This requires that a Kinect is connected at the time of app startup.
            // To make your app robust against plug/unplug, 
            // it is recommended to use KinectSensorChooser provided in Microsoft.Kinect.Toolkit (See components in Toolkit Browser).
            foreach (var potentialSensor in KinectSensor.KinectSensors)
            {
                if (potentialSensor.Status == KinectStatus.Connected)
                {
                    this.sensor = potentialSensor;
                    break;
                }
            }
 
            if (null != this.sensor)
            {
                // Turn on the skeleton stream to receive skeleton frames
                // grip release的识别需要这两种frame, 在后边需要
                this.sensor.SkeletonStream.Enable();
                this.sensor.DepthStream.Enable();
 
                // Add an event handler to be called whenever there is new color frame data
                this.sensor.AllFramesReady += this.SensorAllFramesReady;
 
                // bind gesture related recalls
                // 这里绑定一个Microsoft.Kinect.Toolkit.Interaction.IInteractionClient接口的实现类
                // 下面有详细说明
                interactionClientImp = new InteractionClientImp();
                interactionStream = new InteractionStream(this.sensor, interactionClientImp);
                interactionStream.InteractionFrameReady +=
                    new System.EventHandler<InteractionFrameReadyEventArgs>(SensorInteractionFrameReady);
 
                // Start the sensor!
                try
                {
                    this.sensor.Start();
                }
                catch (IOException)
                {
                    this.sensor = null;
                }
            }
 
            if (null == this.sensor)
            {
                Console.WriteLine("Kinect启动失败!code:"+Properties.Resources.NoKinectReady);
            }

刚才在实例化InteractionStream的时候我们传入了IInteractionClient接口的实现类
这个类是供kinect控件(Kinect.Toolkits.Controls)使用的, 我们不需要使用, 只要实现它, 在他的接口方法中返回固定的值即可, 实现方法参见附件中代码

接下来是响应kinect中“所有帧都准备好了”这个事件

        private void SensorAllFramesReady(object sender, AllFramesReadyEventArgs e)
        {
            Skeleton[] skeletons = new Skeleton[0];
 
            DepthImageFrame depthFrame = e.OpenDepthImageFrame();
 
            SkeletonFrame skeletonFrame = e.OpenSkeletonFrame();
            if (skeletonFrame != null && depthFrame != null)
            {
                skeletons = new Skeleton[skeletonFrame.SkeletonArrayLength];
                skeletonFrame.CopySkeletonDataTo(skeletons);
 
                // 这里就是关键了
                Microsoft.Kinect.Vector4 accelerometerReading = this.sensor.AccelerometerGetCurrentReading();
                interactionStream.ProcessSkeleton(skeletons, accelerometerReading, skeletonFrame.Timestamp);//Grip Release
                interactionStream.ProcessDepth(depthFrame.GetRawPixelData(), depthFrame.Timestamp);
 
            }
            // 这里要显式销毁, 不然会有警告
            if (depthFrame != null)
            {
                depthFrame.Dispose();
            }
            if (skeletonFrame != null)
            {
                skeletonFrame.Dispose();
            }
        }

InteractionStream 对深度图和骨架图处理后一旦发现手势变化(注意, 只有变化的时候)就会呼叫回调方法
如下实现回调方法:

        private void SensorInteractionFrameReady(object sender, InteractionFrameReadyEventArgs e)
        {
            InteractionFrame interactionFrame = e.OpenInteractionFrame();
            if (interactionFrame == null) { return; }
 
            UserInfo[] userInfos = new UserInfo[InteractionFrame.UserInfoArrayLength];
            interactionFrame.CopyInteractionDataTo(userInfos);
 
            if (userInfos == null)
            {
                return;
            }
 
            for (int userIndex = 0; userIndex < userInfos.Length; userIndex++)
            {
                int playerIndex = userIndex;
                UserInfo userInfo = userInfos[userIndex];
                int skeletonTrackingId = userInfo.SkeletonTrackingId;
 
                foreach (InteractionHandPointer interactionHandPointer in userInfo.HandPointers)
                {
                    if (interactionHandPointer.HandType == InteractionHandType.None && interactionHandPointer.IsPrimaryForUser == false && interactionHandPointer.IsActive == false && interactionHandPointer.IsInteractive == false && interactionHandPointer.IsTracked == false)
                    {
                        continue;
                    }
                    if (interactionHandPointer.HandType == InteractionHandType.Left)//左手
                    {
                        if (interactionHandPointer.HandEventType == InteractionHandEventType.None)
                        {
                            continue;
                        }
                        if (interactionHandPointer.HandEventType == InteractionHandEventType.Grip)
                        {
                            Console.WriteLine("左手握住");
                        }
                        if (interactionHandPointer.HandEventType == InteractionHandEventType.GripRelease)
                        {
                            Console.WriteLine("左手张开");
                        }
                    }
                    if (interactionHandPointer.HandType == InteractionHandType.Right)//右手
                    {
                        if (interactionHandPointer.HandEventType == InteractionHandEventType.None)
                        {
                            continue;
                        }
                        if (interactionHandPointer.HandEventType == InteractionHandEventType.Grip)
                        {
                            Console.WriteLine("右手握住");
                        }
                        if (interactionHandPointer.HandEventType == InteractionHandEventType.GripRelease)
                        {
                            Console.WriteLine("右手张开");
                        }
                    }
                }
            }
        }

最后在程序退出时关闭kinect

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (null != this.sensor)
            {
                this.sensor.Stop();
            }
            Application.Exit();
        }

运行的时候要注意
需要将C:\Program Files\Microsoft SDKs\Kinect\Developer Toolkit v1.7.0\Redist\x86\KinectInteraction170_32.dll(根据实际情况修改)拷贝到工程的bin\Debug(根据实际情况修改)目录下

附项目打包:
由于KinectInteraction170_32.dll文件较大, 所以没有放在打包中, 请自行拷贝
GripReleaseDemo

此条目发表在 C#, 体感技术 分类目录。将固定链接加入收藏夹。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>