官方文档
Xbox NUI Camera Drivers Download
Microsoft WDF KinectSensor Interface Driver
Kinect-v2 Examples with MS-SDK(译文二)
Kinect-v2 Examples with MS-SDK Doc(Chinese documents)
Kinect驱动安装目录
C:\Program Files\Microsoft Kinect Drivers\Drivers
一、安装开发环境
1、官方下载 Kinect for Windows SDK 2.0,并安装。
2、测试Kinect设备是否正常工作。
绿勾代表正常工作
有时Kinect connected显示叉,尝试让kinect断开电源10秒以上,再插上。
Kinect V2必须插USB 3.0才能正常工作。USB 2.0、USB 3.1都不行。
设备管理器查看USB接口版本
确保麦克风阵列处于启用状态,否则 Kinect 可能出现工作不稳定。
3、下载示例并导入到Unity2017或更高版本中
百度网盘下载 (Kinect v2 Examples with_2.13.unitypackage) 提取码: 5yjs
百度网盘下载 (Kinect v2 Examples with MS-SDK 2.20.unitypackage) 提取码: aj05
注意: Kinect v2 Examples with MS-SDK 2.20.unitypackage 需要Unity2019.1.0或更高版本、Direct3D11。
=====================================================================================
»KinectManager接口功能
1.检查Kinect是否完成了初始化
if ( KinectManager.IsKinectInitialized() ) { }
2.获取摄像头画面(一般作为背景)
Texture2D background = manager.GetUsersClrTex();
3.判断指定用户的某关节是否正处于跟踪中
long userId = manager.GetUserIdByIndex(0);//0代表第1个用户
int joint = (int)KinectInterop.JointType.HandRight;//判断右手
if (manager.IsJointTracked (userId, joint)) {}
4.获取关节坐标及旋转角
//关节坐标 long userId = manager.GetUserIdByIndex(0); int joint = (int)KinectInterop.JointType.HandRight;//右手 Rect backgroundRect = foregroundCamera.pixelRect; Vector3 posJoint = manager.GetJointPosColorOverlay(userId, joint, foregroundCamera, backgroundRect); //关节旋转角度 Vector3 vForward = foregroundCamera ? foregroundCamera.transform.forward : Vector3.forward; bool objFlipped = (Vector3.Dot(overlayObject.forward, vForward) < 0);//夹角为锐角 Quaternion rotJoint = manager.GetJointOrientation(userId, joint, !objFlipped);
5.获取父关节
KinectInterop.JointType jointParent = manager.GetParentJoint(KinectInterop.JointType.HandRight);
6.是否至少有1个用户被跟踪
if (!manager.IsUserDetected()) {
//没用户时,可以暂停或停止游戏
}
7.判断指定用户ID是否在跟踪用户列表中
if (manager.IsUserTracked(userId)) {}
8.清除所有被跟踪的用户
manager.ClearKinectUsers();//通常在游戏结束时调用
9.骨骼枚举
Kinect中的定义:KinectInterop.JointType
Unity中的定义: HumanBodyBones
PS: 注意定义中的对应关系
例如:KinectInterop.JointType.ShoulderLeft对应的是HumanBodyBones.LeftUpperArm
10.获取骨骼
//获取KinectInterop.JointType.ShoulderLeft
animatorComponent.GetBoneTransform(HumanBodyBones.LeftUpperArm)
11.改变人类化身姿态
//确保对象不为null,且为人类 if (animatorComponent && animatorComponent.avatar && animatorComponent.avatar.isHuman) { HumanPoseHandler humanPoseHandler = new HumanPoseHandler(animatorComponent.avatar, rootTransform); HumanPose humanPose = new HumanPose(); humanPoseHandler.GetHumanPose(ref humanPose); humanPose.bodyPosition = 新值; humanPose.bodyRotation = 新值; humanPose.muscles = 新值;//当前姿势的肌肉值的数组 humanPoseHandler.SetHumanPose(ref humanPose); }
12.刷新姿态监听器列表(通常进入场景后调用一次)
找出场景中实现了KinectGestures.GestureListenerInterface的脚本,并加入到监听列表,同时找出场景中
KinectGestures脚本。
manager.refreshGestureListeners();
13.刷新化身控制器列表(通常进入场景后调用一次)
找出场景中的AvatarController脚本并加入avatarControllers列表
manager.refreshAvatarControllers()
14.获取主用户ID
获取主用户(第一个或最近的用户)的userid,如果没有检测到用户,则获取0
manager.GetPrimaryUserID();
15.获取前景图像(通常指用户)
backManager = BackgroundRemovalManager.Instance; if (backManager && backManager.IsBackgroundRemovalInitialized()) { foregroundTex = (RenderTexture)backManager.GetForegroundTex (); }
前景图像使用的渲染shader为Color2DepthShader.shader,修改此shader可以调整渲染效果。
在 BackgroundRemovalManager 类的 Start() 中替换 sensorData.color2DepthMaterial 可自定义前景渲染材质。
Compute User Map: 必须设置为Body Texture
Compute Color Map: 必须勾选
16.获取坐标点深度值
//获取头部关节坐标 Vector3 posHeadRaw = kinectManager.GetJointKinectPosition(userId, (int)KinectInterop.JointType.Head); if(posHeadRaw != Vector3.zero) { //转到深度坐标系 Vector2 posDepthHead = kinectManager.MapSpacePointToDepthCoords(posHeadRaw); //得到深度值 ushort depthHead = kinectManager.GetDepthForPixel((int)posDepthHead.x, (int)posDepthHead.y); }
17.获取面部矩形区域
if (faceManager.IsFaceTrackingInitialized() && faceManager.IsTrackingFace(userId)) { Rect faceJointRect = faceManager.GetFaceColorRect(userId); }
18.调整前景裁剪边缘
Erode Iterations: 缩小裁剪边缘
Dilate Iterations: 扩大裁剪边缘
19.获取面部模型数据
KinectInterop.SensorData sensorData = kinectManager.GetSensorData(); //获取面部模型顶点数 int iNumVertices = sensorData.sensorInterface.GetFaceModelVerticesCount(0); if (iNumVertices <= 0) return; Vector3[] avModelVertices = new Vector3[iNumVertices]; //获取面部模型顶点 bool bGotModelVertices = sensorData.sensorInterface.GetFaceModelVertices(0, ref avModelVertices); //获取三角形数量 int iNumTriangles = sensorData.sensorInterface.GetFaceModelTrianglesCount(); if(iNumTriangles <= 0) return; //获取三角形顶点索引 int[] avModelTriangles = new int[iNumTriangles]; bool bGotModelTriangles = sensorData.sensorInterface.GetFaceModelTriangles(mirroredModelMesh, ref avModelTriangles); //获取头在kinect中的坐标 Vector3 headPos = Vector3.zero; bGotHeadPos = sensorData.sensorInterface.GetHeadPosition(primaryUserID, ref headPos); //从kinect坐标系转到Unity世界坐标系 Matrix4x4 kinectToWorld = kinectManager ? kinectManager.GetKinectToWorldMatrix() : Matrix4x4.identity; Vector3 headPosWorld = kinectToWorld.MultiplyPoint3x4(headPos); //将顶点坐标从kinect坐标系转到Unity世界坐标 Vector3[] vMeshVertices = new Vector3[avModelVertices.Length]; for(int i = 0; i < avModelVertices.Length; i++) { //世界坐标转面部模型的本地坐标 vMeshVertices[i] = kinectToWorld.MultiplyPoint3x4(avModelVertices[i]) - headPosWorld; } //创建Mesh if (faceModelMesh) { Mesh mesh = new Mesh(); mesh.name = "FaceMesh"; faceModelMesh.GetComponent().mesh = mesh; mesh.vertices = vMeshVertices; mesh.triangles = avModelTriangles; mesh.RecalculateNormals(); } //为面部Mesh设置贴图 Texture texColorMap = kinectManager ? kinectManager.GetUsersClrTex() : null; RenderTexture faceMeshTexture = new RenderTexture(texColorMap.width, texColorMap.height, 0); faceModelMesh.GetComponent ().material.mainTexture = faceMeshTexture; if (faceMeshTexture && texColorMap) { // update the color texture Graphics.Blit(texColorMap, faceMeshTexture); }
20.获取采集图像尺寸
//摄像头采集的图像尺寸 kinectManager.GetColorImageWidth(); kinectManager.GetColorImageHeight(); //红外摄像头采集的深度图像尺寸 kinectManager.GetDepthImageWidth(); kinectManager.GetDepthImageHeight();
21.获取面部模型特征点在Unity中的世界坐标
FacetrackingManager faceManager = FacetrackingManager.Instance; int iVertCount = faceManager.GetUserFaceVertexCount(userId); Vector3[] faceVertices = new Vector3[iVertCount]; //这里的顶点坐标系是Kinect设备 if (faceManager.GetUserFaceVertices(userId, ref faceVertices)) { //Kinect坐标到Unity世界坐标系的转换矩阵 Matrix4x4 kinectToWorld = kinectManager.GetKinectToWorldMatrix(); //面部关键点枚举数组 HighDetailFacePoints[] facePoints = (HighDetailFacePoints[])System.Enum.GetValues(typeof(HighDetailFacePoints)); DictionarydictFacePoints = new Dictionary (); for (int i = 0; i < facePoints.Length; i++) { HighDetailFacePoints point = facePoints[i]; //转换到Unity世界坐标系 dictFacePoints[point] = kinectToWorld.MultiplyPoint3x4(faceVertices[(int)point]); } //让面具模型坐标跟随鼻尖(即,实现面具跟随面部) //NoseTip: 鼻尖 HighDetailFacePoints facePoint = HighDetailFacePoints.NoseTip; Vector3 facePointPos = faceVertices[(int)facePoint]; facePointTransform.position = facePointPos; }
22.调整背景画面显示大小及位置
//显示摄像头画面
KinectManager manager = KinectManager.Instance;
mGUITexture.texture = manager.GetUsersClrTex();
23.设置前景像机(渲染3D物体)与Kinect摄像头的视场角相等
KinectManager manager = KinectManager.Instance;
KinectInterop.SensorData sensorData = manager.GetSensorData();
foregroundCamera.fieldOfView = sensorData.colorCameraFOV;
24.获取关节在Camera坐标系中的坐标
Rect backgroundRect = foregroundCamera.pixelRect; ortraitBackground portraitBack = PortraitBackground.Instance; if(portraitBack && portraitBack.enabled) { backgroundRect = portraitBack.GetBackgroundRect(); } //返回关节在Unity中的世界坐标 Vector3 posColorOverlay = kinectManager.GetJointPosColorOverlay( primaryUserID, (int)KinectInterop.JointType.Head, foregroundCamera, backgroundRect); //让目标3D对象跟随关节 faceModelMesh.transform.position = posColorOverlay;
25.计算面部模型顶点对应的UV贴图坐标
//获取模型顶点坐标 KinectInterop.SensorData sensorData = kinectManager.GetSensorData(); int iNumVertices = sensorData.sensorInterface.GetFaceModelVerticesCount(primaryUserID); Vector3[] avModelVertices = new Vector3[iNumVertices]; sensorData.sensorInterface.GetFaceModelVertices(primaryUserID, ref avModelVertices); //Kinect摄像头采集的画面宽高 float colorWidth = (float)kinectManager.GetColorImageWidth(); float colorHeight = (float)kinectManager.GetColorImageHeight(); //计算模型顶点对应的UV坐标 for(int i = 0; i < avModelVertices.Length; i++) { //顶点对应的深度图坐标 Vector2 posDepth = kinectManager.MapSpacePointToDepthCoords(avModelVertices[i]); if(posDepth != Vector2.zero) { //得到深度值 ushort depth = kinectManager.GetDepthForPixel((int)posDepth.x, (int)posDepth.y); //得到顶点在Color图像中的坐标 Vector2 posColor = kinectManager.MapDepthPointToColorCoords(posDepth, depth); if(posColor != Vector2.zero && !float.IsInfinity(posColor.x) && !float.IsInfinity(posColor.y)) { //转成[0,1]区间的UV坐标 avModelUV[i] = new Vector2(posColor.x / colorWidth, posColor.y / colorHeight); } } } //设置uv mesh.uv = avModelUV; //如果顶点有变化,别忘了重新计算下 mesh.RecalculateNormals(); mesh.RecalculateBounds();
26.获取面部细节点坐标
int NoseTip = (int)Microsoft.Kinect.Face.HighDetailFacePoints.NoseTip; Vector3 NoseTipPos = avModelVertices[NoseTip];//鼻尖坐标
27.表情动画
//获取动画单元(AU)权重值,Shape各动画表情权重值 //AU是中性形状的增量,您可以使用它来对动画化身模型上的目标进行变形, //以使化身像被跟踪的用户一样起作用。例如,AU定义是否张口,抬起眉毛以及其他面部表情细节。 DictionarydictAU = new Dictionary (); sensorData.sensorInterface.GetAnimUnits(userId, ref dictAU); //获取形状单位(SU)权重 //SU估计用户头部的特定形状:眉毛,鼻子,脸颊,嘴巴或下巴等特征的形状。 Dictionary dictSU = new Dictionary (); ensorData.sensorInterface.GetShapeUnits(userId, ref dictSU);
»需要开发人员自己实现的接口:
public class MyGestureListener : KinectGestures.GestureListenerInterface { //用户进入 void UserDetected(long userId, int userIndex) { KinectManager manager = KinectManager.Instance; // 添加希望追踪的用户手势 manager.DetectGesture(userId, KinectGestures.Gestures.SwipeLeft); manager.DetectGesture(userId, KinectGestures.Gestures.SwipeRight); } //用户离开 void UserLost(long userId, int userIndex) { } //返回手势进度 void GestureInProgress(long userId, int userIndex, Gestures gesture, float progress, KinectInterop.JointType joint, Vector3 screenPos) { } //手势完成 //return true(手势必须重新开始) bool GestureCompleted(long userId, int userIndex, Gestures gesture, KinectInterop.JointType joint, Vector3 screenPos) { // 判断手势类型并做出相应处理 switch (gesture) { case KinectGestures.Gestures.SwipeLeft: break; case KinectGestures.Gestures.SwipeRight: break; } //返回true,KinectManager会调用ResetPlayerGestures();意味着手势将重新开始 return true; } //手势取消 bool GestureCancelled(long userId, int userIndex, Gestures gesture, KinectInterop.JointType joint) { //返回true,KinectManager会调用ResetGesture();意味着手势将重新开始 return true; } } public class MyInteractionListener : InteractionListenerInterface { //手握住 void HandGripDetected(long userId, int userIndex, bool isRightHand, bool isHandInteracting, Vector3 handScreenPos) { } //手释放 void HandReleaseDetected(long userId, int userIndex, bool isRightHand, bool isHandInteracting, Vector3 handScreenPos) { } //左手或右手在适当的位置停留至少2.5秒 //return true(手势必须重新开始) bool HandClickDetected(long userId, int userIndex, bool isRightHand, Vector3 handScreenPos) { } }
»手势识别
Kinect手势类型定义在KinectGestures.cs中
KinectGestures.Gestures
public enum Gestures { None = 0, RaiseRightHand,//右手举起过肩并保持至少一秒 RaiseLeftHand,//左手举起过肩并保持至少一秒 Psi,//双手举起过肩并保持至少一秒 Tpose,//触摸 Stop,//双手下垂 Wave,//左手或右手举起来回摆动 Click,//左手或右手在适当的位置停留至少2.5秒 SwipeLeft,//右手向左挥 SwipeRight,//左手向右挥 SwipeUp,//左手或者右手向上挥 SwipeDown,//左手或者右手向下挥 RightHandCursor,//假手势,用来使光标随着手移动 LeftHandCursor,//假手势,用来使光标随着手移动 ZoomIn,//手肘向下,两手掌相聚至少0.7米,然后慢慢合在一起 ZoomOut,//手肘向下,左右手掌合在一起(求佛的手势),然后慢慢分开 Wheel,//想象一下你双手握着方向盘,然后左右转动 Jump,//在1.5秒内髋关节中心至少上升10厘米 (跳) Squat,//在1.5秒内髋关节中心至少下降10厘米 (下蹲) Push,//在1.5秒内将左手或右手向外推 Pull,//在1.5秒内将左手或右手向里拉 ShoulderLeftFront,//左肩前倾 ShoulderRightFront,//右肩前倾 LeanLeft, //身体向左倾斜 LeanRight, //身体向右倾斜 LeanForward,//身体向前倾斜 LeanBack,//身体向后倾斜 KickLeft,//踢左脚 KickRight,//踢右脚 Run,//跑 RaisedRightHorizontalLeftHand,//左手平举 RaisedLeftHorizontalRightHand,//右手平举 //自定义手势 UserGesture1 = 101, UserGesture2 = 102, UserGesture3 = 103, UserGesture4 = 104, UserGesture5 = 105, UserGesture6 = 106, UserGesture7 = 107, UserGesture8 = 108, UserGesture9 = 109, UserGesture10 = 110, }
每种手势的识别处理在KinectGestures.CheckForGesture()方法中,可以在这个方法中扩展自定义手势识别。
Gestures.Push
右手向前推的姿态定义:
1、右手.y - 左肘.y > -0.1米
2、Mathf.Abs(右手.x - 右肩.x) < 0.2米
3、右手.z - 左肘.z < -0.2米
»关节
每个姿态由手、肘、肩、脊柱、臀部、膝、踝关节共同组成,参见KinectGestures.GetNeededJointIndexes()方法:
/// <summary> /// 获取组成姿态的关节索引列表 /// </summary> public virtual int[] GetNeededJointIndexes(KinectManager manager) { //手 leftHandIndex = manager.GetJointIndex(KinectInterop.JointType.HandLeft); rightHandIndex = manager.GetJointIndex(KinectInterop.JointType.HandRight); //肘 leftElbowIndex = manager.GetJointIndex(KinectInterop.JointType.ElbowLeft); rightElbowIndex = manager.GetJointIndex(KinectInterop.JointType.ElbowRight); //肩 leftShoulderIndex = manager.GetJointIndex(KinectInterop.JointType.ShoulderLeft); rightShoulderIndex = manager.GetJointIndex(KinectInterop.JointType.ShoulderRight); //脊柱 hipCenterIndex = manager.GetJointIndex(KinectInterop.JointType.SpineBase); shoulderCenterIndex = manager.GetJointIndex(KinectInterop.JointType.SpineShoulder); //臀部 leftHipIndex = manager.GetJointIndex(KinectInterop.JointType.HipLeft); rightHipIndex = manager.GetJointIndex(KinectInterop.JointType.HipRight); //膝 leftKneeIndex = manager.GetJointIndex(KinectInterop.JointType.KneeLeft); rightKneeIndex = manager.GetJointIndex(KinectInterop.JointType.KneeRight); //踝 leftAnkleIndex = manager.GetJointIndex(KinectInterop.JointType.AnkleLeft); rightAnkleIndex = manager.GetJointIndex(KinectInterop.JointType.AnkleRight); int[] neededJointIndexes = { leftHandIndex, rightHandIndex, leftElbowIndex, rightElbowIndex, leftShoulderIndex, rightShoulderIndex, hipCenterIndex, shoulderCenterIndex, leftHipIndex, rightHipIndex, leftKneeIndex, rightKneeIndex, leftAnkleIndex, rightAnkleIndex }; return neededJointIndexes; }
»只跟踪指定关节
创建XXXAvatarController继承自AvatarController,并重写基类的MapBones()方法。
protected virtual void MapBones()
AvatarController中声明了Kinect关节与Mecanim关节之间的映射关系
//kinect-joints to mecanim-bones mapping //Kinect关节到Mecanim动画系统中的关节映射 protected static readonly Dictionary<int, HumanBodyBones> boneIndex2MecanimMap = new Dictionary<int, HumanBodyBones> { {0, HumanBodyBones.Hips}, {1, HumanBodyBones.Spine}, //{2, HumanBodyBones.Chest}, {3, HumanBodyBones.Neck}, //{4, HumanBodyBones.Head}, {5, HumanBodyBones.LeftUpperArm}, {6, HumanBodyBones.LeftLowerArm}, {7, HumanBodyBones.LeftHand}, //{8, HumanBodyBones.LeftIndexProximal}, //{9, HumanBodyBones.LeftIndexIntermediate}, //{10, HumanBodyBones.LeftThumbProximal}, {11, HumanBodyBones.RightUpperArm}, {12, HumanBodyBones.RightLowerArm}, {13, HumanBodyBones.RightHand}, //{14, HumanBodyBones.RightIndexProximal}, //{15, HumanBodyBones.RightIndexIntermediate}, //{16, HumanBodyBones.RightThumbProximal}, {17, HumanBodyBones.LeftUpperLeg}, {18, HumanBodyBones.LeftLowerLeg}, {19, HumanBodyBones.LeftFoot}, //{20, HumanBodyBones.LeftToes}, {21, HumanBodyBones.RightUpperLeg}, {22, HumanBodyBones.RightLowerLeg}, {23, HumanBodyBones.RightFoot}, //{24, HumanBodyBones.RightToes}, {25, HumanBodyBones.LeftShoulder}, {26, HumanBodyBones.RightShoulder}, {27, HumanBodyBones.LeftIndexProximal}, {28, HumanBodyBones.RightIndexProximal}, {29, HumanBodyBones.LeftThumbProximal}, {30, HumanBodyBones.RightThumbProximal}, }; //kinect手指关节到Mecanim动画系统中的关节映射 protected static readonly Dictionary<int, HumanBodyBones> fingerIndex2MecanimMap = new Dictionary<int, HumanBodyBones> { {0, HumanBodyBones.LeftThumbProximal}, {1, HumanBodyBones.LeftThumbIntermediate}, {2, HumanBodyBones.LeftThumbDistal}, {3, HumanBodyBones.LeftIndexProximal}, {4, HumanBodyBones.LeftIndexIntermediate}, {5, HumanBodyBones.LeftIndexDistal}, {6, HumanBodyBones.LeftMiddleProximal}, {7, HumanBodyBones.LeftMiddleIntermediate}, {8, HumanBodyBones.LeftMiddleDistal}, {9, HumanBodyBones.LeftRingProximal}, {10, HumanBodyBones.LeftRingIntermediate}, {11, HumanBodyBones.LeftRingDistal}, {12, HumanBodyBones.LeftLittleProximal}, {13, HumanBodyBones.LeftLittleIntermediate}, {14, HumanBodyBones.LeftLittleDistal}, {15, HumanBodyBones.RightThumbProximal}, {16, HumanBodyBones.RightThumbIntermediate}, {17, HumanBodyBones.RightThumbDistal}, {18, HumanBodyBones.RightIndexProximal}, {19, HumanBodyBones.RightIndexIntermediate}, {20, HumanBodyBones.RightIndexDistal}, {21, HumanBodyBones.RightMiddleProximal}, {22, HumanBodyBones.RightMiddleIntermediate}, {23, HumanBodyBones.RightMiddleDistal}, {24, HumanBodyBones.RightRingProximal}, {25, HumanBodyBones.RightRingIntermediate}, {26, HumanBodyBones.RightRingDistal}, {27, HumanBodyBones.RightLittleProximal}, {28, HumanBodyBones.RightLittleIntermediate}, {29, HumanBodyBones.RightLittleDistal} }; // get bone transforms from the animator component //Animator animatorComponent = GetComponent<Animator>(); Transform bone = animatorComponent.GetBoneTransform(boneIndex2MecanimMap[boneIndex]); Transform fingerBone = animatorComponent.GetBoneTransform(fingerIndex2MecanimMap[boneIndex]);
using System.Collections; using System.Collections.Generic; using UnityEngine; /// <summary> /// 只绑定上半身骨骼 /// </summary> public class UpperAvatarController : AvatarController { // Public variables that will get matched to bones. If empty, the Kinect will simply not track it. public Transform HipCenter; public Transform Spine; public Transform ShoulderCenter; public Transform Neck; //public Transform Head; public Transform ClavicleLeft; public Transform ShoulderLeft; public Transform ElbowLeft; public Transform HandLeft; public Transform FingersLeft; //private Transform FingerTipsLeft = null; public Transform ThumbLeft; public Transform ClavicleRight; public Transform ShoulderRight; public Transform ElbowRight; public Transform HandRight; public Transform FingersRight; //private Transform FingerTipsRight = null; public Transform ThumbRight; public Transform HipLeft; public Transform KneeLeft; public Transform FootLeft; //private Transform ToesLeft = null; public Transform HipRight; public Transform KneeRight; public Transform FootRight; //private Transform ToesRight = null; [Tooltip("The body root node (optional).")] public Transform BodyRoot; // Offset node this transform is relative to, if any (optional) //public GameObject OffsetNode; // If the bones to be mapped have been declared, map that bone to the model. protected override void MapBones() { bones[0] = HipCenter; bones[1] = Spine; bones[2] = ShoulderCenter; bones[3] = Neck; //bones[4] = Head; bones[5] = ShoulderLeft; bones[6] = ElbowLeft; bones[7] = HandLeft; //bones[8] = FingersLeft; //bones[9] = FingerTipsLeft; //bones[10] = ThumbLeft; bones[11] = ShoulderRight; bones[12] = ElbowRight; bones[13] = HandRight; //bones[14] = FingersRight; //bones[15] = FingerTipsRight; //bones[16] = ThumbRight; bones[17] = HipLeft; bones[18] = KneeLeft; bones[19] = FootLeft; //bones[20] = ToesLeft; bones[21] = HipRight; bones[22] = KneeRight; bones[23] = FootRight; //bones[24] = ToesRight; // special bones bones[25] = ClavicleLeft; bones[26] = ClavicleRight; bones[27] = FingersLeft; bones[28] = FingersRight; bones[29] = ThumbLeft; bones[30] = ThumbRight; // body root and offset bodyRoot = BodyRoot; } }
»动态加载kinect配置参数
kinect.xml
<?xml version="1.0" encoding="UTF-8"?> <root> <!-- 以下参数名与Kinect Manager(Script)属性面板中的参数对应 --> <SensorHeight>1</SensorHeight> <SensorAngle>0</SensorAngle> <!-- DontUse, ShowInfoOnly, AutoUpdate, AutoUpdateAndShowInfo --> <AutoHeightAngle>DontUse</AutoHeightAngle> <!-- None, RawUserDepth, BodyTexture, UserTexture, CutOutTexture --> <ComputeUserMap>RawUserDepth</ComputeUserMap> <ComputeColorMap>true</ComputeColorMap> <ComputeInfraredMap>false</ComputeInfraredMap> <DisplayUserMap>false</DisplayUserMap> <DisplayColorMap>false</DisplayColorMap> <DisplaySkeletonLines>false</DisplaySkeletonLines> <DisplayMapsWidthPercent>20</DisplayMapsWidthPercent> <UseMultiSourceReader>true</UseMultiSourceReader> <MinUserDistance>0.5</MinUserDistance> <MaxUserDistance>0</MaxUserDistance> <MaxLeftRightDistance>0</MaxLeftRightDistance> <MaxTrackedUsers>6</MaxTrackedUsers> <ShowTrackedUsersOnly>true</ShowTrackedUsersOnly> <!-- Appearance, Distance, LeftToRight --> <UserDetectionOrder>Appearance</UserDetectionOrder> <IgnoreInferredJoints>false</IgnoreInferredJoints> <IgnoreZCoordinates>false</IgnoreZCoordinates> <LateUpdateAvatars>false</LateUpdateAvatars> <SkipRemoteAvatars>false</SkipRemoteAvatars> <!-- None, Default, Light, Medium, Aggressive --> <Smoothing>Default</Smoothing> <UseBoneOrientationConstraints>false</UseBoneOrientationConstraints> <EstimateJointVelocities>false</EstimateJointVelocities> <!-- None, Default, Light, Medium, Aggressive --> <VelocitySmoothing>Light</VelocitySmoothing> <AllowTurnArounds>false</AllowTurnArounds> <!-- None, Default, All --> <AllowedHandRotations>Default</AllowedHandRotations> <WaitTimeBeforeRemove>1</WaitTimeBeforeRemove> <!-- None = 0,RaiseRightHand, RaiseLeftHand, Psi, Tpose, Stop, Wave, Click, SwipeLeft, SwipeRight, SwipeUp, SwipeDown, RightHandCursor, LeftHandCursor, ZoomIn, Wheel, Jump, Squat, Push, Pull, ShoulderLeftFront, ShoulderRightFront, LeanLeft, LeanRight, LeanForward, LeanBack, KickLeft, KickRight, Run, RaisedRightHorizontalLeftHand, // by Andrzej W RaisedLeftHorizontalRightHand, UserGesture1 = 101, UserGesture2 = 102, UserGesture3 = 103, UserGesture4 = 104, UserGesture5 = 105, UserGesture6 = 106, UserGesture7 = 107, UserGesture8 = 108, UserGesture9 = 109, UserGesture10 = 110, --> <PlayerCalibrationPose>None</PlayerCalibrationPose> <MinTimeBetweenGestures>0.7</MinTimeBetweenGestures> </root>
KinectConfig.cs
// 与kinect.xml对应 public static class KinectConfig { public static float SensorHeight { get; private set; } public static float SensorAngle { get; private set; } public static bool ComputeColorMap { get; private set; } public static bool ComputeInfraredMap { get; private set; } public static bool DisplayUserMap { get; private set; } public static bool DisplayColorMap { get; private set; } public static bool DisplaySkeletonLines { get; private set; } public static float DisplayMapsWidthPercent { get; private set; } public static bool UseMultiSourceReader { get; private set; } public static float MinUserDistance { get; private set; } public static float MaxUserDistance { get; private set; } public static float MaxLeftRightDistance { get; private set; } public static int MaxTrackedUsers { get; private set; } public static bool ShowTrackedUsersOnly { get; private set; } public static bool IgnoreInferredJoints { get; private set; } public static bool IgnoreZCoordinates { get; private set; } public static bool LateUpdateAvatars { get; private set; } public static bool SkipRemoteAvatars { get; private set; } public static bool UseBoneOrientationConstraints { get; private set; } public static bool EstimateJointVelocities { get; private set; } public static bool AllowTurnArounds { get; private set; } public static float WaitTimeBeforeRemove { get; private set; } public static float MinTimeBetweenGestures { get; private set; } public static KinectManager.AutoHeightAngle AutoHeightAngle = KinectManager.AutoHeightAngle.DontUse; public static KinectManager.UserMapType ComputeUserMap = KinectManager.UserMapType.RawUserDepth; public static KinectManager.UserDetectionOrder UserDetectionOrder = KinectManager.UserDetectionOrder.Appearance; public static KinectManager.Smoothing Smoothing = KinectManager.Smoothing.Default; public static KinectManager.Smoothing VelocitySmoothing = KinectManager.Smoothing.Light; public static KinectManager.AllowedRotations AllowedHandRotations = KinectManager.AllowedRotations.Default; public static KinectGestures.Gestures PlayerCalibrationPose; public static bool Done { get; private set; } // 加载配置 public static void Load(string path) { if (!File.Exists(path)) { Debug.LogErrorFormat("Not found: {0}", path); return; } XmlDocument xml = new XmlDocument(); xml.Load(path); Parse(xml); } // 读入配置到kinect public static void Read(KinectManager kinect) { if (kinect == null) { Debug.Log("[KinectConfig] Read(null)"); return; } if (!Done) { Debug.Log("[KinectConfig] Unparse completion"); return; } kinect.sensorHeight = SensorHeight; kinect.sensorAngle = SensorAngle; kinect.computeColorMap = ComputeColorMap; kinect.computeInfraredMap = ComputeInfraredMap; kinect.displayUserMap = DisplayUserMap; kinect.displayColorMap = DisplayColorMap; kinect.displaySkeletonLines = DisplaySkeletonLines; kinect.DisplayMapsWidthPercent = DisplayMapsWidthPercent; kinect.useMultiSourceReader = UseMultiSourceReader; kinect.minUserDistance = MinUserDistance; kinect.maxUserDistance = MaxUserDistance; kinect.maxLeftRightDistance = MaxLeftRightDistance; kinect.maxTrackedUsers = MaxTrackedUsers; kinect.showTrackedUsersOnly = ShowTrackedUsersOnly; kinect.ignoreInferredJoints = IgnoreInferredJoints; kinect.ignoreZCoordinates = IgnoreZCoordinates; kinect.lateUpdateAvatars = LateUpdateAvatars; kinect.skipRemoteAvatars = SkipRemoteAvatars; kinect.useBoneOrientationConstraints = UseBoneOrientationConstraints; kinect.estimateJointVelocities = EstimateJointVelocities; kinect.allowTurnArounds = AllowTurnArounds; kinect.waitTimeBeforeRemove = WaitTimeBeforeRemove; kinect.minTimeBetweenGestures = MinTimeBetweenGestures; kinect.autoHeightAngle = AutoHeightAngle; kinect.computeUserMap = ComputeUserMap; kinect.userDetectionOrder = UserDetectionOrder; kinect.smoothing = Smoothing; kinect.velocitySmoothing = VelocitySmoothing; kinect.allowedHandRotations = AllowedHandRotations; kinect.playerCalibrationPose = PlayerCalibrationPose; } // 解析配置 private static void Parse(XmlDocument xml) { Type type = Type.GetType("KinectConfig"); XmlNode root = xml.SelectSingleNode("/root"); XmlNodeList childList = root.ChildNodes; for (int i = 0; i < childList.Count; i++) { XmlNode node = childList.Item(i); if (node.NodeType == XmlNodeType.Comment) //跳过XML中的注释 continue; string text = node.InnerText; PropertyInfo property = type.GetProperty(node.Name); FieldInfo field = type.GetField(node.Name); if (property == null && field == null) { Debug.LogErrorFormat("[KinectConfig] Parse Error, node.Name={0}, MemberType={1}", node.Name, type.MemberType); continue; } if (property != null) { bool IsInt = property.PropertyType == typeof(int); bool IsFloat = property.PropertyType == typeof(float); bool IsBool = property.PropertyType == typeof(bool); if (IsInt) property.SetValue(null, int.Parse(text)); else if (IsFloat) property.SetValue(null, float.Parse(text)); else if (IsBool) property.SetValue(null, bool.Parse(text)); } if (field != null) { if (field.FieldType.IsEnum) { System.Object obj = Enum.Parse(field.FieldType, text); field.SetValue(null, obj); } } } Done = true; Debug.Log(ToString()); } public static string ToString() { StringBuilder sb = new StringBuilder(); sb.Append("Kinect配置信息\n\n<color=blue>"); Type type = Type.GetType("KinectConfig"); PropertyInfo[] propertyInfos = type.GetProperties(); for (int i=0; i< propertyInfos.Length; i++) { PropertyInfo p = propertyInfos[i]; sb.AppendFormat("{0}={1}\n", p.Name, p.GetValue(null)); } FieldInfo[] fieldInfos = type.GetFields(); for (int i = 0; i < fieldInfos.Length; i++) { FieldInfo p = fieldInfos[i]; sb.AppendFormat("{0}={1}\n", p.Name, p.GetValue(null)); } sb.Append("</color>"); return sb.ToString(); } }
»打包发布
注意:需要手动将kinect相关的dll从工程目录拷到发布目录下。