# 前言

据说,前几天据说公司接到一个委托,可能要做 Kinect 相关的一些东西:比如小游戏或者其他一些功能之类的。
所以,就要用到 Kinect 了,平台么... 自然是 Unity3D 了。

曾经我也说过了吧,这个公司 Unity3D、UE4、AR、VR、MR..... 什么的大约都是要搞的,所以,昨天就研究了下 Kinect。

# 安装及配置

# 下载

首先,公司买的 Kinect 是 v2 版本的,百度一下 “Kinect V2” 看看图片就可明白了:左边一个摄像头模样,右边一个 XBOX 的图标。
还是来张图片吧:

Kinect V2

首先,老样子。既然要开发,那就得下载 SDK 了。
Kinect 驱动及官方 SDK:https://developer.microsoft.com/zh-cn/windows/kinect

接着是适用于 Unity3D 的插件 —— 虽然很多人说是可用 AssetStore 里边的,不过貌似现在都没更新了。
为了谨慎起见,还是用微软官方提供的 Unity3D 插件吧:
Unity Pro 程序包:https://developer.microsoft.com/zh-cn/windows/kinect/tools

在这个页面,点击 “Unity Pro 程序包” 即可下载。
如图:

# 安装

东西都下载了,接下来是安装。

首先,需要说明的一点是:Kinect2.0 的 SDK 仅支持 Win8 及以上的系统,所以,若还在使用 Win7 的话.... 赶紧换了吧,不然就不要想接下来的事儿了。

然后,安装之前先把 Kinect 的从 USB 接口拔出来,安装完成之后,再插上去。
若是没问题,那么插上去的时候,Kinect 就会自动安装驱动(如果没有的话,那么请检查下是否插入的是 USB3.0 的接口,或者稍稍拔起插下试试,USB 连接这儿也会有所影响 [在下当时便费了些许功夫调式此处,因为这儿还有可能会造成连接之后,相机 Frame 无法读取的问题,表现就是运行时,中间的红灯一闪一闪])。

完成之后,可于 “设备管理器” 中查看,如图:

为了检验下,这时还可打开 “Kinect SDKBrower2.0”,点开 Kinect Configuration Verifier,运行,可以检测 Kinect 相关的详细情形。
如图:

若是这样,那么安装就已经 OK 了。

# Unity3D 开发测试

# 示例

接下来,打开 Unity3D,新建项目,导入之前下载的 “KinectForWindows_UnityPro_2.0.1410” 压缩包中的 “Kinect.2.0.1410.19000.unitypackage”。
然后将其中的示例 KinectView 文件夹复制至 Assets 目录下,便可运行场景进行测试了。

在此,可以看见一张彩色图像及一张深度图及一个根据深度对彩色图采样的 Mesh。

注意:若是还想看 GreenScreen 示例的话,直接复制进来,其中自带的一个 Shader 会报错。
这儿可以这样改一下:

Texture2D _MainTex; 

改为

UNITY_DECLARE_TEX2D(_MainTex);

后面 frag 函数中的

//o = _MainTex.Sample(SampleType, i.tex);

改为

o = UNITY_SAMPLE_TEX2D(_MainTex, i.tex);

即可解决。

# 测试

为了测试,我自己写了一个小脚本:功能主要就是实现一个 UI,表示右手的位置,握拳,就截取一张图片:

s
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Windows.Kinect;
public class Test : MonoBehaviour
{
    private KinectSensor _sensor;
    private Body[] _bodys;
    private BodyFrameReader _bodyFrameReader;
    private HashSet<Body> _bodySet = new HashSet<Body>();
    [SerializeField]
    private Image _hand;
    [SerializeField]
    private Sprite _handClosed;
    [SerializeField]
    private Sprite _handOpen;
    [SerializeField]
    private Sprite _handUnkown;
    private Vector3 _pos;
    // Use this for initialization
    void Start()
    {
        _sensor = KinectSensor.GetDefault();
        if (!_sensor.IsOpen)
            _sensor.Open();
        if (_sensor != null)
        {
            _bodyFrameReader = _sensor.BodyFrameSource.OpenReader();
            _bodys = new Body[_bodyFrameReader.BodyFrameSource.BodyCount];
        }
    }
    // Update is called once per frame
    void Update()
    {
        if (_sensor != null)
        {
            using (BodyFrame bodyFrame = _bodyFrameReader.AcquireLatestFrame())
            {
                if (bodyFrame != null)
                {
                    bodyFrame.GetAndRefreshBodyData(_bodys);
                    foreach (var body in _bodys)
                    {
                        if (body.IsTracked)
                        {
                            _bodySet.Add(body);
                            Windows.Kinect.Joint jo = body.Joints[JointType.HandRight];
                            if (jo.TrackingState != TrackingState.NotTracked)
                            {
                                _pos = new Vector3(jo.Position.X, jo.Position.Y, jo.Position.Z);
                                _hand.transform.position = new Vector3((jo.Position.X + 1) / 2 * Screen.width, (jo.Position.Y + 1) / 2 * Screen.height, 0);
                                //print(_hand.transform.position);
                            }
                            switch (body.HandRightState)
                            {
                                case HandState.Unknown:
                                    _hand.color = Color.blue;
                                    _hand.sprite = _handUnkown;
                                    break;
                                case HandState.NotTracked:
                                    _hand.color = Color.red;
                                    _hand.sprite = _handUnkown;
                                    break;
                                case HandState.Open:
                                    _hand.color = Color.green;
                                    _hand.sprite = _handOpen;
                                    break;
                                case HandState.Closed:
                                    _hand.color = Color.green;
                                    _hand.sprite = _handClosed;
                                    // 握拳的时候,就截取一张图片
                                    Application.CaptureScreenshot(Application.dataPath + "/../ScreenCapture.png");
                                    break;
                                case HandState.Lasso:
                                    _hand.color = Color.yellow;
                                    _hand.sprite = _handUnkown;
                                    break;
                                default:
                                    break;
                            }
                        }
                    }
                }
            }
        }
    }
    private Vector2 _slider;
    private void OnGUI()
    {
        GUIStyle style = new GUIStyle();
        style.fontSize = 50;
        style.normal.textColor = Color.red;
        GUILayout.Label(_hand.transform.position + "    " + _pos, style);
        _slider = GUILayout.BeginScrollView(_slider);
        foreach (var body in _bodySet)
        {
            //if (!body.IsTracked) return;
            GUILayout.BeginVertical(GUI.skin.box);
            GUILayout.Label("对象:" + body.TrackingId);
            var activities = body.Activities;
            GUILayout.Label("-------> Activities: " + body.ClippedEdges);
            foreach (var act in activities)
            {
                GUILayout.Label(act.Key + ":  " + act.Value);
            }
            GUILayout.Label("-------> Appearance: ");
            foreach (var app in body.Appearance)
            {
                GUILayout.Label(app.Key + "  " + app.Value);
            }
            GUILayout.Label("-------> ClippedEdges: " + body.ClippedEdges);
            GUILayout.Label("-------> Expressions: ");
            foreach (var item in body.Expressions)
            {
                GUILayout.Label(item.Key + "  " + item.Value);
            }
            GUILayout.Label("-------> HandLeftConfidence: " + body.HandLeftConfidence);
            GUILayout.Label("-------> HandLeftState: " + body.HandLeftState);
            GUILayout.Label("-------> HandRightConfidence: " + body.HandRightConfidence);
            GUILayout.Label("-------> HandRightState: " + body.HandRightState);
            GUILayout.Label("-------> IsRestricted: " + body.IsRestricted);
            GUILayout.Label("-------> IsTracked: " + body.IsTracked);
            GUILayout.Label("-------> Lean: " + body.Lean);
            GUILayout.Label("-------> LeanTrackingState: " + body.LeanTrackingState);
            GUILayout.EndVertical();
        }
        GUILayout.EndScrollView();
    }
    private void OnApplicationQuit()
    {
        _sensor.Close();
    }
}

下边就是我截取得一张图片:

右边很诡异的图像就是之前提到的根据深度图采样的 Mesh 了,越靠近相机,就越近,反之越远。

# 结语

这就是最简单的一个测试了,各种信息皆有,那么根据 API 提供的信息,便可衍生出更多的功能。

另外,Kinect 似乎也不受支持了,比如若是有心,便可注意到 Kinect 的 SDK 甚至都是两、三年前的东西了,亦即是说:微软已经两三年没为其提供支持.... 了么?

以上。