最近越来越觉得封装一个模块之前,得写个文档来整理下思路,可以达到事半功倍的效果
使用Kinect来获取关节点位置计算关节的旋转角,用于做mesh deformation
-------------------------
Kinect模块
要完成的事:
1. 生成用于显示的图像信息,使用opencv进行
<1> 显示深度图
需要传入深度图元数据DepthMetaData的对象,可以传入其指针
<2> 显示骨骼
需要获得骨骼的二维坐标,openni里的做法是使用UserGenerator里的骨骼功能获取指定的关节对象,使用枚举变量来指定具体的关节
然后使用DepthGenerator的ConvertRealWorldToProjective将关节点的空间坐标转换到投射坐标,用投射坐标来绘制关节点
<3> 显示文字信息
显示什么文字,以及在什么位置显示文字,什么时候显示文字,对于这些信息均需要了解,可以存储几个全局变量来存放这些信息
在程序中的其他位置更改这些全局变量,而在绘图处则仅需简单的使用这些全局变量
绘图的顺序应该遵循先绘制深度图,然后骨骼,然后文字的顺序,以防止覆盖
2. 获取关节点位置
获取所有的关节点位置,存放于一个数组当中,这个数组用于
<1> 提取出5个树枝的三维数组,用于计算旋转角
<2> 获取关节点的二维坐标,用于1中的骨骼绘制
Openni里使用XnSkeletonJointPosition来存储关节点
typedef struct XnSkeletonJointPosition
{
XnVector3D position;
XnConfidence fConfidence;
} XnSkeletonJointPosition;
XnSkeletonJoint这个枚举对象用来指定关节点
typedef enum XnSkeletonJoint
{
XN_SKEL_HEAD = 1,
XN_SKEL_NECK = 2,
XN_SKEL_TORSO = 3,
XN_SKEL_WAIST = 4,
XN_SKEL_LEFT_COLLAR = 5,
XN_SKEL_LEFT_SHOULDER = 6,
XN_SKEL_LEFT_ELBOW = 7,
XN_SKEL_LEFT_WRIST = 8,
XN_SKEL_LEFT_HAND = 9,
XN_SKEL_LEFT_FINGERTIP =10,
XN_SKEL_RIGHT_COLLAR =11,
XN_SKEL_RIGHT_SHOULDER =12,
XN_SKEL_RIGHT_ELBOW =13,
XN_SKEL_RIGHT_WRIST =14,
XN_SKEL_RIGHT_HAND =15,
XN_SKEL_RIGHT_FINGERTIP =16,
XN_SKEL_LEFT_HIP =17,
XN_SKEL_LEFT_KNEE =18,
XN_SKEL_LEFT_ANKLE =19,
XN_SKEL_LEFT_FOOT =20,
XN_SKEL_RIGHT_HIP =21,
XN_SKEL_RIGHT_KNEE =22,
XN_SKEL_RIGHT_ANKLE =23,
XN_SKEL_RIGHT_FOOT =24
} XnSkeletonJoint
所以可以定义一个XnSkeletonJoint的数组,然后向这个数组填充数据
添加回调程序来了解程序的状态:
m_UserGenerator.RegisterUserCallbacks( User_NewUser, User_LostUser, NULL, hUserCallbacks );
m_UserGenerator.GetSkeletonCap().SetSkeletonProfile(XN_SKEL_PROFILE_ALL);
m_UserGenerator.GetSkeletonCap().RegisterCalibrationCallbacks(&CalibrationStart, &CalibrationEnd, NULL, hCalibrationCallbacks);
m_UserGenerator.GetPoseDetectionCap().RegisterToPoseCallbacks(&User_PoseDetected, NULL, NULL, hPoseCallbacks);
这里分别为新增用户、丢失用户,姿势检测,用户标定开始和用户标定结束注册了回调函数
这几个回调函数发生的顺序分别是
新增用户à姿势检测à用户标定开始à用户标定结束,丢失用户在用户丢失的时候发出通知
要获取骨骼数据,必须要开启姿势识别,使用UserGenerator里面的SkeletonCapability对象成员的函数StartPoseDetection("Psi", user);
这样在Psi姿势检测成功的时候就会调用上面注册的回调函数,姿势检测成功并不意味着骨骼的检测成功(用户成功被标定),但是要使骨骼被成功检测,则必须是姿势先检测成功,姿势检测成功是骨骼检测成功的充分不必要条件
在用户标定结束的回调函数里面有参数指明用户是否被成功标定,假如标定失败,则要重新开始姿势检测
从这里可以看出,回调函数做的主要的事可以是报告程序的状态,以及在用户没被成功标定的情况下重启姿势检测
关节数据的填充:
调用UserGenerator里SkeletonCapability成员的方法
GetSkeletonJointPosition(XnUserID user, XnSkeletonJoint eJoint, XnSkeletonJointPosition& Joint)可以获取关节点位置
在哪里对关节点数组进行填充?
关节点在骨骼成功标定后,每一帧都会发生更新,所以要在每一帧都对关节点数组进行填充,可以在调用绘制深度图函数的那个函数里,在这里面要先做一个判断,即用户标定是否成功,假如成功,才可以对关节数组进行更新
使用UserGenerator里的SkeletonCapability对象的IsTracking函数可以获得指定的用户已经被成功标定并正被跟踪,假如IsTracking返回真,就获取所有的关节点数据
3.关节点数组的后处理
openni获取的关节点经常是不全的,所以对于一些关键点,需要进行补全或者是在遇到错误关节点的时候,进行怎么样的处理
为了更好的进行处理,首先从这些关节点中把人体五个肢体的关节点提取出来,即左右手、左右腿、躯干,然后在这五个肢体中进行补全或其他处理