Kinect+Unity之手势识别初探

来源:互联网 发布:python做网站的服务器 编辑:程序博客网 时间:2024/06/05 20:55

前几天环境配好了,连上Kinect能跑示例项目KinectView。花了很大的力气找插件的API手册,原来插件并没有官方手册,目前官网也只有两个示例项目。于是自己看代码,想首先学会怎样写一个手势触发特定事件。主要看了BodySourceManager.cs和BodySourceView.cs,中午成功写出了如果左手高过头顶,自动截屏保存图片。

思路是if判断,如果左手的y坐标值大于等于头顶的y坐标值条件为真,触发事件,调用Unity的一个API叫Application.Capturescreenshot()。在BodySourceView.cs中的RefreshBodyObject()函数中修改,这个函数会在Update()中调用,每一帧都会更新。红框部分是自己添加的代码,其余均为无改动的示例源码。




Kinect.JoinType可以按F12查看插件中的源代码,可知是枚举类型,如图

                                                           

简要分析一下示例程序中的RefreshBodyObejct函数。这个函数主要做的是获取关节点坐标,在Unity中画出人体骨骼。画骨骼直接用Unity的线渲染LineRender(在前面代码中已经调用它的SetVertexCount方法设置画得线有两个端点)。遍历Dictionary类型的_Bonemap(保存的是Key-Value键值对,Value是Key的下一个关联结点),key就是画线段的源位置,value就是线段的目标位置。

完整代码如下

BodySourceManager.csusing UnityEngine;using System.Collections;using Windows.Kinect;public class BodySourceManager : MonoBehaviour {    private KinectSensor _Sensor;    private BodyFrameReader _Reader;    private Body[] _Data = null;        public Body[] GetData()    {        return _Data;    }        void Start ()     {        _Sensor = KinectSensor.GetDefault();        if (_Sensor != null)        {            _Reader = _Sensor.BodyFrameSource.OpenReader();                        if (!_Sensor.IsOpen)            {                _Sensor.Open();            }        }       }        void Update ()     {        if (_Reader != null)        {            var frame = _Reader.AcquireLatestFrame();            if (frame != null)            {                if (_Data == null)                {                    _Data = new Body[_Sensor.BodyFrameSource.BodyCount];                }                           frame.GetAndRefreshBodyData(_Data);                frame.Dispose();                frame = null;            }        }        }        void OnApplicationQuit()    {        if (_Reader != null)        {            _Reader.Dispose();            _Reader = null;        }                if (_Sensor != null)        {            if (_Sensor.IsOpen)            {                _Sensor.Close();            }                        _Sensor = null;        }    }}


<pre name="code" class="csharp">BodySourceView.csusing UnityEngine;using System.Collections;using System.Collections.Generic;using Kinect = Windows.Kinect;public class BodySourceView : MonoBehaviour {    public Material BoneMaterial;    public GameObject BodySourceManager;        private Dictionary<ulong, GameObject> _Bodies = new Dictionary<ulong, GameObject>();    private BodySourceManager _BodyManager;        private Dictionary<Kinect.JointType, Kinect.JointType> _BoneMap = new Dictionary<Kinect.JointType, Kinect.JointType>()    {        { Kinect.JointType.FootLeft, Kinect.JointType.AnkleLeft },        { Kinect.JointType.AnkleLeft, Kinect.JointType.KneeLeft },        { Kinect.JointType.KneeLeft, Kinect.JointType.HipLeft },        { Kinect.JointType.HipLeft, Kinect.JointType.SpineBase },                { Kinect.JointType.FootRight, Kinect.JointType.AnkleRight },        { Kinect.JointType.AnkleRight, Kinect.JointType.KneeRight },        { Kinect.JointType.KneeRight, Kinect.JointType.HipRight },        { Kinect.JointType.HipRight, Kinect.JointType.SpineBase },                { Kinect.JointType.HandTipLeft, Kinect.JointType.HandLeft },        { Kinect.JointType.ThumbLeft, Kinect.JointType.HandLeft },        { Kinect.JointType.HandLeft, Kinect.JointType.WristLeft },        { Kinect.JointType.WristLeft, Kinect.JointType.ElbowLeft },        { Kinect.JointType.ElbowLeft, Kinect.JointType.ShoulderLeft },        { Kinect.JointType.ShoulderLeft, Kinect.JointType.SpineShoulder },                { Kinect.JointType.HandTipRight, Kinect.JointType.HandRight },        { Kinect.JointType.ThumbRight, Kinect.JointType.HandRight },        { Kinect.JointType.HandRight, Kinect.JointType.WristRight },        { Kinect.JointType.WristRight, Kinect.JointType.ElbowRight },        { Kinect.JointType.ElbowRight, Kinect.JointType.ShoulderRight },        { Kinect.JointType.ShoulderRight, Kinect.JointType.SpineShoulder },                { Kinect.JointType.SpineBase, Kinect.JointType.SpineMid },        { Kinect.JointType.SpineMid, Kinect.JointType.SpineShoulder },        { Kinect.JointType.SpineShoulder, Kinect.JointType.Neck },        { Kinect.JointType.Neck, Kinect.JointType.Head },    };        void Update ()     {        if (BodySourceManager == null)        {            return;        }                _BodyManager = BodySourceManager.GetComponent<BodySourceManager>();        if (_BodyManager == null)        {            return;        }        Kinect.Body[] data = _BodyManager.GetData();//GetData();        if (data == null)        {            return;        }                List<ulong> trackedIds = new List<ulong>();        foreach(var body in data)        {            if (body == null)            {                continue;              }                            if(body.IsTracked)            {                trackedIds.Add (body.TrackingId);            }        }                List<ulong> knownIds = new List<ulong>(_Bodies.Keys);                // First delete untracked bodies        foreach(ulong trackingId in knownIds)        {            if(!trackedIds.Contains(trackingId))//List方法测试一个元素是否在List内            {                Destroy(_Bodies[trackingId]);//先Destroy掉GameObject                _Bodies.Remove(trackingId);//再将键值对从_Bodies字典中移除            }        }        foreach(var body in data)        {            if (body == null)            {                continue;            }                        if(body.IsTracked)            {                if(!_Bodies.ContainsKey(body.TrackingId))                {                    _Bodies[body.TrackingId] = CreateBodyObject(body.TrackingId);                }                                RefreshBodyObject(body, _Bodies[body.TrackingId]);            }        }    }        private GameObject CreateBodyObject(ulong id)    {        GameObject body = new GameObject("Body:" + id);                for (Kinect.JointType jt = Kinect.JointType.SpineBase; jt <= Kinect.JointType.ThumbRight; jt++)        {            GameObject jointObj = GameObject.CreatePrimitive(PrimitiveType.Cube);                        LineRenderer lr = jointObj.AddComponent<LineRenderer>();            lr.SetVertexCount(2);//设置线段数            lr.material = BoneMaterial;//物体的材质            lr.SetWidth(0.05f, 0.05f);//设置线的开始和结束宽度                        jointObj.transform.localScale = new Vector3(0.3f, 0.3f, 0.3f);            jointObj.name = jt.ToString();            jointObj.transform.parent = body.transform;        }                return body;    }        private void RefreshBodyObject(Kinect.Body body, GameObject bodyObject)    {        for (Kinect.JointType jt = Kinect.JointType.SpineBase; jt <= Kinect.JointType.ThumbRight; jt++)        {            Kinect.Joint sourceJoint = body.Joints[jt];            Kinect.Joint? targetJoint = null;                        if(_BoneMap.ContainsKey(jt))            {                targetJoint = body.Joints[_BoneMap[jt]];//所以之前字典中设置就是一个一个关节连起来            }                        Transform jointObj = bodyObject.transform.FindChild(jt.ToString());            jointObj.localPosition = GetVector3FromJoint(sourceJoint);                        LineRenderer lr = jointObj.GetComponent<LineRenderer>();            if(targetJoint.HasValue)            {//Debug.Log (jointObj.localPosition);ok                lr.SetPosition(0, jointObj.localPosition);                lr.SetPosition(1, GetVector3FromJoint(targetJoint.Value));                lr.SetColors(GetColorForState (sourceJoint.TrackingState), GetColorForState(targetJoint.Value.TrackingState));            }            else            {                lr.enabled = false;            }if(body.Joints[Kinect.JointType.HandLeft].Position.Y>=body.Joints[Kinect.JointType.Head].Position.Y){Debug.Log("handleft:"+body.Joints[Kinect.JointType.HandLeft].Position.Y);Debug.Log("head:"+body.Joints[Kinect.JointType.Head].Position.Y);Debug.Log("My LeftHand is Higher than head!~");Application.CaptureScreenshot ("Screenshoot.png", 0);}        }    }        private static Color GetColorForState(Kinect.TrackingState state)    {        switch (state)        {        case Kinect.TrackingState.Tracked:            return Color.green;        case Kinect.TrackingState.Inferred:            return Color.red;        default:            return Color.black;        }    }        private static Vector3 GetVector3FromJoint(Kinect.Joint joint)    {        return new Vector3(joint.Position.X * 10, joint.Position.Y * 10, joint.Position.Z * 10);    }}



自己琢磨代码还是很开心的,代码值得完整的分析在此不赘述了。写博文是有点折腾,但是今天看到别人的技术博客和心得分享真的是很励志(http://www.the5fire.com/  http://blog.csdn.net/the_fire?viewmode=list)。



0 0
原创粉丝点击