新买的xbox360 kinect更新包出了点问题,怎么办

如何解决kinect在动态动作识别开发的问题_百度知道
如何解决kinect在动态动作识别开发的问题
提问者采纳
非商业转载请注明出处:HMM学习笔记_1(从一个实例中学习DTW算法)作者,它表示了一个Pose。商业转载请联系作者获得授权,这样可以消除近大远小及人体高矮胖瘦不同带来的差异).com/question//answer/来源:http。然后记录某个标准的Pose序列作为一个Action模板。DTW算法运行效率比较高.zhihu,想学的话可以看下面这个教程:把Kinect骨骼帧提供的25个节点的X
来自团队:
其他类似问题
为您推荐:
kinect的相关知识
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁10231人阅读
Kinect(17)
OpenCV(19)
坠露木兰(4)
Kinect人脸跟踪Kinect Face Tracking SDK
本文持续维护地址:
(资源不是最新的,请复制下面代码替换相应的文件)
[]编译程序时遇到xcopy问题(error MSB3073),给出了他的解决办法(第4节)。
[]程序源代码由进行了改进,避免了人脸走出检测后窗体假死情况(第6节)。
2.人脸跟踪概念
& &(1)软件硬件配置
& &(2)face tracking参数
& &(3)具体技术
& &(4)函数和结构
& &(5)人脸跟踪简易流程
3.更多人脸跟踪细节介绍
& &(1)线程问题
& &(2)人脸特征点
& &(3)人脸旋转
4.程序配置与说明
5.参考资源
6.程序源代码
-----------------------------------------------------------------------------------
&&&&&& 自上篇Kinect SDK 1.5 Face Tracking文章出现后(),许多人阅读到了(CSDN,博客园,百度文库),相关代码也被上百次下载(百度文库、csdn)。已经过去很久了,但是国内依旧没有发现很好的关于这方面的博客(大家都藏着掖着吗)。当时我对于C++中的多线程还半知半解,如今多次使用有些熟悉。
&&&&&& 之所以Kinect中的Face Tracking没有得到很多的关注,我想主要原因还是这个方法必须使用Kinect硬件(真不便宜啊,普通摄像头几十块ok了),只适合开发Kinect室内应用。其次这个Face Tracking也是很耗CPU的,一般的双核电脑一旦运行经常会占用90%多的CPU。题外话,微软有许多强大的算法,比如人脸跟踪(基于普通彩色摄像头),但是他们只给了Windows Phone下的API,却不给出PC下的。我也去天津参加过Kinect的会议,遇到一些微软的产品,确实做得很强大很稳健,人脸检测用改进的特征进行Adaboost,之后用AAM进行面部特征点跟踪,十分稳健。去年参加了不少面试,国内的很多公司都在做人脸识别,但真正有实力的只有大公司弄的好。但如果说你想靠这个Kinect的人脸识别混饭吃,有点困难,除非你研究AAM人脸跟踪算法再去研究人脸识别、表情识别、三维建模等算法才会有饭吃。
&&&&&& 鉴于之前没有对Kinect的Face Tracking进行详细描述和探讨,直接暴力的给出相关代码,有必要给出更详细的文章和更好的代码。
------------------------------------------------------------------------------------
2.人脸跟踪概念
&&&&&& 首先现在大部分开发都针对Kinect for windows(目前1900RMB,还是有点贵的)了,但这个face tracking SDK在xbox版的Kinect依旧可以运行,自然精度会不好。Kinect for windows的深度数据是640*480的,而xbox的是320*240。而彩色的RGB摄像头也清晰不少,这点官方没有具体介绍,但实际效果好很多。如果要做研究,自然使用贵很多的Kinect for windows了(这样也导致了个人一般不会去玩这个传感器),不过对于学校、公司这点钱不多。下面默认使用Kinect
for windows,但代码稍加修改在xbox的kinect上也能运作。
--------------------------------------------------
(1)软件硬件配置
Kinect for Windows有如下要求:
采用下列操作系统的一种:
嵌入式Windows 标准7
嵌入式WindowsPOSReady 7
32位(x86)或64位(x64) 处理器
双核2.66-GHz 或更快的处理器(建议使用i7)
专用USB 2.0总线
&&&&&& 从Kinect SDK 1.5开始的Kinect for windows开发工具包中含有人脸追踪模块,当前最新的是SDK1.6。在近几个星期里,将会有新的SDK会更新。新的SDK将会带来简单的动作识别(手握拳和张开)和Kinect Fusion三维实时建模。
--------------------------------------------------
(2)face tracking参数
&&&&&& 依赖于你PC的CPU能力,人脸跟踪引擎使用4~8ms对一帧图像进行人脸跟踪,仅仅只依赖于CPU(没有使用GPU)。
&&&&&& 将会影响跟踪准确率的因素:
&&&&&& A.光照:光线应该充足,没有太多阴影或者太强的侧光。也就是光照要均匀,并且足够。
&&&&&& B.距离:距离Kinect的距离,距离体感越近则跟踪效果越好,当小于1.5m时,跟踪的效果是最好的,因为越近深度数据越精确。当然也不能太近了,如果小于0.5m,深度数据都无法获取,或者人脸遮住摄像头了,也无法跟踪。
&&&&&& C.遮挡:戴厚眼镜或者Lincoln那样的胡子,人脸跟踪会有问题,这点还是需要改善的方面。
&&&&&& 使用了Active Apperance Model作为二维特征跟踪器,然后我们把计算模型扩展到我们的Kinect深度数据上,然后它可以跟踪三维的人脸,这样使得它比二维特征点跟踪器稳健。AAM算法对于真实世界的情况不是很稳健。一些算法:、,.
--------------------------------------------------
(3)具体技术
坐标系统:
使用了Kinect的坐标系统来输出三维跟踪结果(x,y,z)。Z轴是传感器到用户的距离,Y轴是上下指向。数据都是以米为计量单位(这样一般会读出2.xxx,1.xxx之类的浮点数值),角度都是旋转角度(不是弧度)。
上图是输出的三维面具在kinect的坐标下情况。
输入图像:
彩色图像和深度图像。其实还需要一个人头和脖子的三维坐标。
--------------------------------------------------
(4)函数和结构
人脸追踪的SDK是免注册的COM对象。主要有4个COM接口
IFTFaceTracker:人脸追踪主要接口。
IFTResult:人脸追踪运算的结果。
IFTImage:图像缓冲区,类似OpenCV的Mat。
IFTModel:三维人脸模型
还有一些结构:
FT_SENSOR_DATA:包含用于人脸追踪所有所需的输入数据。
FT_CAMERA_CONFIG:包含彩色或者深度传感器的信息。
FT_VECTOR2D:二维向量。也就是(x,y),(x,y)…
FT_VECTOR3D:三维向量。
FT_TRIANGLE:三维模型人脸角度。
FT_WEIGHTED_RECT:权重矩阵。
--------------------------------------------------
(5)人脸跟踪简易流程
&&&&& 不论是1个人的还是2个人的追踪,都差不多。一般追踪距离摄像头比较近的人,骨骼数据可能有时无法获取(那就使用上一帧的就是,经验之谈,因为很随机)。
-----------------------------------------------------------------------------------
3.更多人脸跟踪细节介绍
&&&&&& 这里介绍一些实际开发时遇到的问题。
(1)线程问题
&&&&&& 一般至少2个线程,微软给的例子(FaceTrackingVisualization)一个是获取彩色、深度、骨骼的线程,另一个线程直接调用使用这三个数据,把数据传给人脸跟踪模块,都没进行线程同步。我有点疑问,不同步会不会有问题,但怎么运行测试都木有问题。每次跟踪后它都Sleep(16)一下,这个数值自己可以修改,我在win32应用里使用Sleep(30)运行结果不错,而在MFC中也使用Sleep(16)。
&&&&&& 这里还需要特别说明的是,千万小心对于原始数据的操作,也就是彩色、深度数据的操作。如果你想显示数据,请拷贝数据后另行处理,不要直接在数据上进行处理,否则会出现很麻烦的问题。你以为把数据传给跟踪模块后,就可以直接在彩色数据(IFTImage)上进行更改了,但在你更改后,人脸跟踪模块由于设置的是16ms,马上又调用人脸跟踪,丢失了人脸模型!这样会出现一种结果:人脸跟踪十分不稳定,面具随机在人脸附近跳动,人脸一旦运动快点,跟踪会发生失效。所以之后我学乖了,要对数据处理或者显示,另外拷贝一份,其实拷贝图像数据是瞬间的事情。
(2)人脸特征点
&&&&&& 微软在face tracking介绍给了一张的人脸图像,这里我就不给图像了,因为那张人脸特征点图像不论是位置还是下标都是不符的。这里我给出我得到的图像
&&&&&& 上图有121个特征点(有些点重复,有些不存在)微软的面部特征点符合Candide-3标准,我们可以在文献(Candide-3_-_an_updated_parameterised_face)中阅读到一张表Appendix A: The CANDIDE -3Vertices and the Corresponding MPEG -4 Facial Feature Points。它列出了113个顶点(下标从0开始),这些顶点的定义和程序中获取的数组一一对应,还多出来的部分可以无视掉。
&&&&&& 这张图像是使用OpenCV显示人脸跟踪数组中的顶点结果,我们可以自己修改程序画出来,需要注意的就是把图像画大一些,否则字符串会重叠在一起。之所以我用线连起来,主要为了看上去更方便,如果一百多个数字显示在图片上,肯定没人想去研究。我把数字按顺序一次连接,发现某些点可以连接出如图所示的线段图。至于每个点到底什么意思,还是要对照表中定义。
&&&&&& 显然这么多点,我们只取需要的点即可。这个仁者见仁智者见智吧。
下图是顶点定义的那张表:
(3)人脸旋转
&&&&&& 获取人脸跟踪结果后,我们除了得到面部关键顶点还可以直接获取人脸朝向(Get3DPose函数)。下图是人脸朝向的定义:
Pitch angle
-90 = looking down towards the floor
+90 = looking up towards the ceiling
Face Tracking tracks when the user’s head pitch is less than 20 degrees, but works best when less than 10 degrees.
Roll angle
0 = neutral
-90 = horizontal parallel with right shoulder of subject
+90 = horizontal parallel with left shoulder of the subject
Face Tracking tracks when the user’s head roll is less than 90 degrees, but works best when less than 45 degrees.
0 = neutral
-90 = turned towards the right shoulder of the subject
+90 = turned towards the left shoulder of the subject
Face Tracking tracks when the user’s head yaw is less than 45 degrees, but works best when less than 30 degrees
&&&&&& 自然如果你做简单的人头旋转头部动作识别,肯定得用到这块。如果你做人脸标表情、动作或者三维建模,也少不了使用这个旋转角度对人脸进行一些仿射变换。很显然,Roll方向上的人脸旋转可以消除掉(我在我的人脸识别中就这样)。如果你使用OpenCV进行放射旋转,要熟悉矩阵旋转公式,一旦人脸旋转,那么所有的顶点坐标都要跟着旋转,如果扣除人脸区域,那么相应的人脸顶点坐标也要减去x轴和y轴的数值。还有需要考虑一些临界情况,比如人脸从左侧移除,人脸从上方、下方走出,会不会导致程序崩溃?此时的人脸数据不可以使用。
&&&&&& 之后还有动画单元等概念,也是可以通过函数直接获取结果,这部分我未进行研究,如果做表情或者人脸动画,则需要深入研究下。
----------------------------------------------------------------------------------
4.程序配置与说明
&&&&&& 对于Win32程序。如果只想看效果,不想研究代码,安装好后,可以直接点击Debug下的exe应用程序进行运行即可。如果想研究代码,需要配置OpenCV环境(),随便你使用OpenCV2.x某个版本,建议使用目前最新的。之所以使用OpenCV,是因为用它显示视频会十分简单,用到的代码也不多。
[]配置方法和解决xcopy方法由提供。
4.1配制方法
首先按照自己电脑上opencv的库文件地址、包含目录地址、库文件,将它们添加到相应的配置属性中
下方的OpenCV244\opencv\,,,,,配置在上方可添加路径区域效果是一样的,即:
包含目录配置:
4.2编译程序遇到xcopy问题
如果在编译运行的时候,遇见关于“xcopy”的问题
在配置属性中生成事件-&后期生成事件中删除命令行的内容就可以了
-----------------------------------------------------------------------------------
5.参考网站和资源:
[shi]Kinect for windows SDK1.5人脸识别与跟踪
[yangecnu, 杨洋]Kinect for Windows SDK开发入门(十六)面部追踪上【C#】
[箫鸣] Kinect SDK 1.5 Face Tracking ---& 使用opencv显示后的超级简化版本
一些官方资源:
Kinect官网
How To Use Kinect Face Tracking SDK
Candide标准
Face Tracking
【需要翻墙】
最后如果有任何问题,或者想一起讨论最好去我的留言,因为留言会自动发送到我的邮箱里面。也可以私信我的。还有文章应该会不断更新,在我的网站()上对应标题的文章会进行持续更新。欢迎大家分享相关知识,上篇kinect人脸跟踪文章写出后快一年了,中国这么大也未有人与我讨论。
-----------------------------------------------------------------------------------
6.程序源代码
[]程序由kexin_0311进行了改进,避免了人脸走出检测后窗体假死情况。
[]修正了对face tracking窗口按下ESC不响应的问题(逻辑问题),去除了cout显示的参数。
// win32_KinectFaceTracking.cpp : 定义控制台应用程序的入口点。
/****************************************************
程序用途:KinectFace Tracking简单例子
开发环境:VisualStudio 2010 win32程序
OpenCV2.4.4 显示界面库
Kinect SDK v1.6 驱动版本
Windows 7 操作系统
开发人员:箫鸣
开发时间:~
联系方式:/guoming0000
备注:另有配套相关博客文章:
Kinect Face Tracking SDK[Kinect人脸跟踪]
******************************************************/
#include &stdafx.h&
#include &windows.h&
#include &opencv2\opencv.hpp&
#include &mmsystem.h&
#include &assert.h&
//#include &strsafe.h&
#include &NuiApi.h&
using namespace
//----------------------------------------------------
#define _WINDOWS
#include &FaceTrackLib.h&
//显示网状人脸,初始化人脸模型
HRESULT VisualizeFaceModel(IFTImage* pColorImg, IFTModel* pModel, FT_CAMERA_CONFIG const* pCameraConfig, FLOAT const* pSUCoef,
FLOAT zoomFactor, POINT viewOffset, IFTResult* pAAMRlt, UINT32 color);//pColorImg为图像缓冲区,pModel三维人脸模型
//---图像大小等参数--------------------------------------------
#define COLOR_WIDTH
#define COLOR_HIGHT
#define DEPTH_WIDTH
#define DEPTH_HIGHT
#define SKELETON_WIDTH 640
#define SKELETON_HIGHT 480
#define CHANNEL
BYTE DepthBuf[DEPTH_WIDTH*DEPTH_HIGHT*CHANNEL];
//---人脸跟踪用到的变量------------------------------------------
IFTImage* pColorFrame,*pColorD
//彩色图像数据,pColorDisplay是用于处理的深度数据
IFTImage* pDepthF
//深度图像数据
FT_VECTOR3D m_hint3D[2];
//头和肩膀中心的坐标
//----各种内核事件和句柄-----------------------------------------------------------------
HANDLE m_hNextColorFrameE
HANDLE m_hNextDepthFrameE
HANDLE m_hNextSkeletonE
HANDLE m_pColorStreamH//保存图像数据流的句柄,用以提取数据
HANDLE m_pDepthStreamH
HANDLE m_hEvNuiProcessS//用于结束的事件对象
//-----------------------------------------------------------------------------------
//获取彩色图像数据,并进行显示
int DrawColor(HANDLE h)
const NUI_IMAGE_FRAME * pImageFrame = NULL;
HRESULT hr = NuiImageStreamGetNextFrame( h, 0, &pImageFrame );
if( FAILED( hr ) )
cout&&&Get Color Image Frame Failed&&&
return -1;
INuiFrameTexture * pTexture = pImageFrame-&pFrameT
NUI_LOCKED_RECT LockedR
pTexture-&LockRect( 0, &LockedRect, NULL, 0 );//提取数据帧到LockedRect中,包括两个数据对象:pitch表示每行字节数,pBits第一个字节的地址
if( LockedRect.Pitch != 0 )//如果每行字节数不为0
BYTE * pBuffer = (BYTE*) LockedRect.pB//pBuffer指向数据帧的第一个字节的地址
//该函数的作用是在LockedRect第一个字节开始的地址复制min(pColorFrame-&GetBufferSize(), UINT(pTexture-&BufferLen()))个字节到pColorFrame-&GetBuffer()所指的缓冲区
memcpy(pColorFrame-&GetBuffer(), PBYTE(LockedRect.pBits), //PBYTE表示无符号单字节数值
min(pColorFrame-&GetBufferSize(), UINT(pTexture-&BufferLen())));//GetBuffer()它的作用是返回一个可写的缓冲指针
//OpenCV显示彩色视频
Mat temp(COLOR_HIGHT,COLOR_WIDTH,CV_8UC4,pBuffer);
imshow(&ColorVideo&,temp);
int c = waitKey(1);//按下ESC结束
//如果在视频界面按下ESC,q,Q都会导致整个程序退出
if( c == 27 || c == 'q' || c == 'Q' )
SetEvent(m_hEvNuiProcessStop);
NuiImageStreamReleaseFrame( h, pImageFrame );
//获取深度图像数据,并进行显示
int DrawDepth(HANDLE h)
const NUI_IMAGE_FRAME * pImageFrame = NULL;
HRESULT hr = NuiImageStreamGetNextFrame( h, 0, &pImageFrame );
if( FAILED( hr ) )
cout&&&Get Depth Image Frame Failed&&&
return -1;
INuiFrameTexture * pTexture = pImageFrame-&pFrameT
NUI_LOCKED_RECT LockedR
pTexture-&LockRect( 0, &LockedRect, NULL, 0 );
if( LockedRect.Pitch != 0 )
USHORT * pBuff = (USHORT*) LockedRect.pB//注意这里需要转换,因为每个数据是2个字节,存储的同上面的颜色信息不一样,这里是2个字节一个信息,不能再用BYTE,转化为USHORT
pDepthBuffer = pB
memcpy(pDepthFrame-&GetBuffer(), PBYTE(LockedRect.pBits),
min(pDepthFrame-&GetBufferSize(), UINT(pTexture-&BufferLen())));
for(int i=0;i&DEPTH_WIDTH*DEPTH_HIGHT;i++)
BYTE index = pBuff[i]&0x07;//提取ID信息
USHORT realDepth = (pBuff[i]&0xFFF8)&&3;//提取距离信息
BYTE scale = 255 - (BYTE)(256*realDepth/0x0fff);//因为提取的信息时距离信息
DepthBuf[CHANNEL*i] = DepthBuf[CHANNEL*i+1] = DepthBuf[CHANNEL*i+2] = 0;
switch( index )
DepthBuf[CHANNEL*i]=scale/2;
DepthBuf[CHANNEL*i+1]=scale/2;
DepthBuf[CHANNEL*i+2]=scale/2;
DepthBuf[CHANNEL*i]=
DepthBuf[CHANNEL*i+1]=
DepthBuf[CHANNEL*i+2]=
DepthBuf[CHANNEL*i]=
DepthBuf[CHANNEL*i+1]=
DepthBuf[CHANNEL*i]=
DepthBuf[CHANNEL*i+2]=
DepthBuf[CHANNEL*i+1]=
DepthBuf[CHANNEL*i+2]=
DepthBuf[CHANNEL*i]=255-scale/2;
DepthBuf[CHANNEL*i+1]=255-scale/2;
DepthBuf[CHANNEL*i+2]=255-scale/2;
Mat temp(DEPTH_HIGHT,DEPTH_WIDTH,CV_8UC3,DepthBuf);
imshow(&DepthVideo&,temp);
int c = waitKey(1);//按下ESC结束
if( c == 27 || c == 'q' || c == 'Q' )
SetEvent(m_hEvNuiProcessStop);
NuiImageStreamReleaseFrame( h, pImageFrame );
//获取骨骼数据,并进行显示
int DrawSkeleton()
NUI_SKELETON_FRAME SkeletonF//骨骼帧的定义
cv::Point pt[20];
Mat skeletonMat=Mat(SKELETON_HIGHT,SKELETON_WIDTH,CV_8UC3,Scalar(0,0,0));
//直接从kinect中提取骨骼帧
HRESULT hr = NuiSkeletonGetNextFrame( 0, &SkeletonFrame );
if( FAILED( hr ) )
cout&&&Get Skeleton Image Frame Failed&&&
return -1;
bool bFoundSkeleton =
for( int i = 0 ; i & NUI_SKELETON_COUNT ; i++ )
if( SkeletonFrame.SkeletonData[i].eTrackingState == NUI_SKELETON_TRACKED )
bFoundSkeleton =
// 跟踪到了骨架
if( bFoundSkeleton )
NuiTransformSmooth(&SkeletonFrame,NULL);
for( int i = 0 ; i & NUI_SKELETON_COUNT ; i++ )
if( SkeletonFrame.SkeletonData[i].eTrackingState == NUI_SKELETON_TRACKED )
for (int j = 0; j & NUI_SKELETON_POSITION_COUNT; j++)
NuiTransformSkeletonToDepthImage( SkeletonFrame.SkeletonData[i].SkeletonPositions[j], &fx, &fy );
pt[j].x = (int) ( fx * SKELETON_WIDTH )/320;
pt[j].y = (int) ( fy * SKELETON_HIGHT )/240;
circle(skeletonMat,pt[j],5,CV_RGB(255,0,0));
// cout&&&one people&&&
cv::line(skeletonMat,pt[NUI_SKELETON_POSITION_SHOULDER_CENTER],pt[NUI_SKELETON_POSITION_SPINE],CV_RGB(0,255,0));
cv::line(skeletonMat,pt[NUI_SKELETON_POSITION_SPINE],pt[NUI_SKELETON_POSITION_HIP_CENTER],CV_RGB(0,255,0));
cv::line(skeletonMat,pt[NUI_SKELETON_POSITION_HEAD],pt[NUI_SKELETON_POSITION_SHOULDER_CENTER],CV_RGB(0,255,0));
cv::line(skeletonMat,pt[NUI_SKELETON_POSITION_HAND_RIGHT],pt[NUI_SKELETON_POSITION_WRIST_RIGHT],CV_RGB(0,255,0));
cv::line(skeletonMat,pt[NUI_SKELETON_POSITION_WRIST_RIGHT],pt[NUI_SKELETON_POSITION_ELBOW_RIGHT],CV_RGB(0,255,0));
cv::line(skeletonMat,pt[NUI_SKELETON_POSITION_ELBOW_RIGHT],pt[NUI_SKELETON_POSITION_SHOULDER_RIGHT],CV_RGB(0,255,0));
cv::line(skeletonMat,pt[NUI_SKELETON_POSITION_SHOULDER_RIGHT],pt[NUI_SKELETON_POSITION_SHOULDER_CENTER],CV_RGB(0,255,0));
cv::line(skeletonMat,pt[NUI_SKELETON_POSITION_SHOULDER_CENTER],pt[NUI_SKELETON_POSITION_SHOULDER_LEFT],CV_RGB(0,255,0));
cv::line(skeletonMat,pt[NUI_SKELETON_POSITION_SHOULDER_LEFT],pt[NUI_SKELETON_POSITION_ELBOW_LEFT],CV_RGB(0,255,0));
cv::line(skeletonMat,pt[NUI_SKELETON_POSITION_ELBOW_LEFT],pt[NUI_SKELETON_POSITION_WRIST_LEFT],CV_RGB(0,255,0));
cv::line(skeletonMat,pt[NUI_SKELETON_POSITION_WRIST_LEFT],pt[NUI_SKELETON_POSITION_HAND_LEFT],CV_RGB(0,255,0));
m_hint3D[0].x=SkeletonFrame.SkeletonData[i].SkeletonPositions[NUI_SKELETON_POSITION_SHOULDER_CENTER].x;
m_hint3D[0].y=SkeletonFrame.SkeletonData[i].SkeletonPositions[NUI_SKELETON_POSITION_SHOULDER_CENTER].y;
m_hint3D[0].z=SkeletonFrame.SkeletonData[i].SkeletonPositions[NUI_SKELETON_POSITION_SHOULDER_CENTER].z;
m_hint3D[1].x=SkeletonFrame.SkeletonData[i].SkeletonPositions[NUI_SKELETON_POSITION_HEAD].x;
m_hint3D[1].y=SkeletonFrame.SkeletonData[i].SkeletonPositions[NUI_SKELETON_POSITION_HEAD].y;
m_hint3D[1].z=SkeletonFrame.SkeletonData[i].SkeletonPositions[NUI_SKELETON_POSITION_HEAD].z;
// cout&&&(&&&m_hint3D[0].x&&&,&&&m_hint3D[0].y&&&,&&&m_hint3D[0].z&&&)&&&
// cout&&&(&&&m_hint3D[1].x&&&,&&&m_hint3D[1].y&&&,&&&m_hint3D[1].z&&&)&&&endl&&
imshow(&SkeletonVideo&,skeletonMat);
waitKey(1);
int c = waitKey(1);//按下ESC结束
if( c == 27 || c == 'q' || c == 'Q' )
SetEvent(m_hEvNuiProcessStop);
DWORD WINAPI KinectDataThread(LPVOID pParam)//线程函数
HANDLE hEvents[4] = {m_hEvNuiProcessStop,m_hNextColorFrameEvent,
m_hNextDepthFrameEvent,m_hNextSkeletonEvent};//内核事件
int nEventI
nEventIdx=WaitForMultipleObjects(sizeof(hEvents)/sizeof(hEvents[0]),
hEvents,FALSE,100);
if (WAIT_OBJECT_0 == WaitForSingleObject(m_hEvNuiProcessStop, 0))
// Process signal events
if (WAIT_OBJECT_0 == WaitForSingleObject(m_hNextColorFrameEvent, 0))
DrawColor(m_pColorStreamHandle);//获取彩色图像并进行显示
if (WAIT_OBJECT_0 == WaitForSingleObject(m_hNextDepthFrameEvent, 0))
DrawDepth(m_pDepthStreamHandle);
if (WAIT_OBJECT_0 == WaitForSingleObject(m_hNextSkeletonEvent, 0))
DrawSkeleton();
//这种方式关闭程序时可能出问题
// switch(nEventIdx)
// case 0:
// case 1:
// DrawColor(m_pVideoStreamHandle);
// case 2:
// DrawDepth(m_pDepthStreamHandle);
// case 3:
// DrawSkeleton();
CloseHandle(m_hEvNuiProcessStop);
m_hEvNuiProcessStop = NULL;
CloseHandle( m_hNextSkeletonEvent );
CloseHandle( m_hNextDepthFrameEvent );
CloseHandle( m_hNextColorFrameEvent );
int main()
m_hint3D[0].x=0;//肩膀的中心坐标,三维向量
m_hint3D[0].y=0;
m_hint3D[0].z=0;
m_hint3D[1].x=0;//头的中心坐标,三维向量
m_hint3D[1].y=0;
m_hint3D[1].z=0;
//使用微软提供的API来操作Kinect之前,要进行NUI初始化
HRESULT hr = NuiInitialize(NUI_INITIALIZE_FLAG_USES_DEPTH_AND_PLAYER_INDEX|NUI_INITIALIZE_FLAG_USES_COLOR|NUI_INITIALIZE_FLAG_USES_SKELETON);
if( hr != S_OK )//Kinect提供了两种处理返回值的方式,就是判断上面的函数是否执行成功。
cout&&&NuiInitialize failed&&&
//1、Color ----打开KINECT设备的彩色图信息通道
m_hNextColorFrameEvent = CreateEvent( NULL, TRUE, FALSE, NULL );//创建一个windows事件对象,创建成功则返回事件的句柄
m_pColorStreamHandle = NULL;//保存图像数据流的句柄,用以提取数据
//打开KINECT设备的彩色图信息通道,并用m_pColorStreamHandle保存该流的句柄,以便于以后读取
hr = NuiImageStreamOpen(NUI_IMAGE_TYPE_COLOR,NUI_IMAGE_RESOLUTION_640x480, 0, 2, m_hNextColorFrameEvent, &m_pColorStreamHandle);
if( FAILED( hr ) )
cout&&&Could not open image stream video&&&
//2、Depth -----打开Kinect设备的深度图信息通道
m_hNextDepthFrameEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
m_pDepthStreamHandle = NULL;//保存深度数据流的句柄,用以提取数据
//打开KINECT设备的深度图信息通道,并用m_pDepthStreamHandle保存该流的句柄,以便于以后读取
hr = NuiImageStreamOpen( NUI_IMAGE_TYPE_DEPTH_AND_PLAYER_INDEX, NUI_IMAGE_RESOLUTION_320x240, 0, 2, m_hNextDepthFrameEvent, &m_pDepthStreamHandle);
if( FAILED( hr ) )
cout&&&Could not open depth stream video&&&
//3、Skeleton -----定义骨骼信号事件句柄,打开骨骼跟踪事件
m_hNextSkeletonEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
hr = NuiSkeletonTrackingEnable( m_hNextSkeletonEvent, NUI_SKELETON_TRACKING_FLAG_ENABLE_IN_NEAR_RANGE|NUI_SKELETON_TRACKING_FLAG_ENABLE_SEATED_SUPPORT);
if( FAILED( hr ) )
cout&&&Could not open skeleton stream video&&&
//4、用于结束的事件对象
m_hEvNuiProcessStop = CreateEvent(NULL,TRUE,FALSE,NULL);
//5、开启一个线程---用于读取彩色、深度、骨骼数据,该线程用于调用线程函数KinectDataThread,线程函数对深度读取彩色和深度图像并进行骨骼跟踪,同时进行显示
HANDLE m_hProcesss = CreateThread(NULL, 0, KinectDataThread, 0, 0, 0);
////////////////////////////////////////////////////////////////////////
//m_hint3D[0] = FT_VECTOR3D(0, 0, 0);//头中心坐标,初始化
//m_hint3D[1] = FT_VECTOR3D(0, 0, 0);//肩膀的中心坐标
pColorFrame
= FTCreateImage();//彩色图像数据,数据类型为IFTImage*
pDepthFrame
= FTCreateImage();//深度图像数据
pColorDisplay = FTCreateImage();
//----------1、创建一个人脸跟踪实例-----------------------
IFTFaceTracker* pFT = FTCreateFaceTracker();//返回数据类型为IFTFaceTracker*
return -1;// Handle errors
//初始化人脸跟踪所需要的数据数据-----FT_CAMERA_CONFIG包含彩色或深度传感器的信息(长,宽,焦距)
FT_CAMERA_CONFIG myCameraConfig = {COLOR_WIDTH, COLOR_HIGHT, NUI_CAMERA_COLOR_NOMINAL_FOCAL_LENGTH_IN_PIXELS}; // width, height, focal length
FT_CAMERA_CONFIG depthConfig = {DEPTH_WIDTH, DEPTH_HIGHT, NUI_CAMERA_DEPTH_NOMINAL_FOCAL_LENGTH_IN_PIXELS};
//depthConfig.FocalLength = NUI_CAMERA_DEPTH_NOMINAL_FOCAL_LENGTH_IN_PIXELS;
//depthConfig.Width
= DEPTH_WIDTH;
//depthConfig.Height
= DEPTH_HIGHT;//这里一定要填,而且要填对才行!!
//IFTFaceTracker的初始化, --- 人脸跟踪主要接口IFTFaceTracker的初始化
hr = pFT-&Initialize(&myCameraConfig, &depthConfig, NULL, NULL);
if( FAILED(hr) )
return -2;// Handle errors
// 2、----------创建一个实例接受3D跟踪结果----------------
IFTResult* pFTResult = NULL;
hr = pFT-&CreateFTResult(&pFTResult);
if(FAILED(hr))
return -11;
// prepare Image and SensorData for 640x480 RGB images
if(!pColorFrame)
return -12;// Handle errors
// Attach assumes that the camera code provided by the application
// is filling the buffer cameraFrameBuffer
//申请内存空间
pColorDisplay-&Allocate(COLOR_WIDTH, COLOR_HIGHT, FTIMAGEFORMAT_UINT8_B8G8R8X8);
hr = pColorFrame-&Allocate(COLOR_WIDTH, COLOR_HIGHT, FTIMAGEFORMAT_UINT8_B8G8R8X8);
if (FAILED(hr))
hr = pDepthFrame-&Allocate(DEPTH_WIDTH, DEPTH_HIGHT, FTIMAGEFORMAT_UINT16_D13P3);
if (FAILED(hr))
//填充FT_SENSOR_DATA结构,包含用于人脸追踪所需要的所有输入数据
FT_SENSOR_DATA
sensorData.ZoomFactor = 1.0f;
sensorData.ViewOffset =//POINT(0,0)
bool isTracked
=//跟踪判断条件
iFaceTrackTimeCount=0;
// 跟踪人脸
while ( 1 )
sensorData.pVideoFrame = pColorF//彩色图像数据
sensorData.pDepthFrame = pDepthF//深度图像数据
//初始化追踪,比较耗时
if(!isTracked)//为false
//会耗费较多cpu计算资源,开始跟踪
hr = pFT-&StartTracking(&sensorData, NULL, m_hint3D, pFTResult);//输入为彩色图像,深度图像,人头和肩膀的三维坐标
if(SUCCEEDED(hr) && SUCCEEDED(pFTResult-&GetStatus()))
isTracked =
isTracked =
//继续追踪,很迅速,它一般使用一个已大概知晓的人脸模型,所以它的调用不会消耗多少cpu计算,pFTResult存放跟踪的结果
hr = pFT-&ContinueTracking(&sensorData, m_hint3D, pFTResult);
if(FAILED(hr) || FAILED (pFTResult-&GetStatus()))
isTracked =
if(isTracked)
IFTModel* ftM//三维人脸模型
hr = pFT-&GetFaceModel(&ftModel);//得到三维人脸模型
pSU = NULL;
pFT-&GetShapeUnits(NULL, &pSU, &numSU, &suConverged);
POINT viewOffset = {0, 0};
pColorFrame-&CopyTo(pColorDisplay,NULL,0,0);//将彩色图像pColorFrame复制到pColorDisplay中,然后对pColorDisplay进行直接处理
hr = VisualizeFaceModel(pColorDisplay, ftModel, &myCameraConfig, pSU, 1.0, viewOffset, pFTResult, 0x00FFFF00);//该函数为画网格
if(FAILED(hr))
printf(&显示失败!!\n&);
Mat tempMat(COLOR_HIGHT,COLOR_WIDTH,CV_8UC4,pColorDisplay-&GetBuffer());
imshow(&faceTracking&,tempMat);
bStop = waitKey(1);//按下ESC结束
else// -----------当isTracked = false时,则值显示获取到的彩色图像信息
pColorFrame-&CopyTo(pColorDisplay,NULL,0,0);
Mat tempMat(COLOR_HIGHT,COLOR_WIDTH,CV_8UC4,pColorDisplay-&GetBuffer());
imshow(&faceTracking&,tempMat);
bStop = waitKey(1);
if(m_hEvNuiProcessStop!=NULL)
if( bStop == 27 || bStop == 'q' || bStop == 'Q' )
SetEvent(m_hEvNuiProcessStop);
if(m_hProcesss!=NULL)
WaitForSingleObject(m_hProcesss,INFINITE);
CloseHandle(m_hProcesss);
m_hProcesss = NULL;
//这里也要判断是否m_hEvNuiProcessStop已经被激活了!
Sleep(16);
// iFaceTrackTimeCount++;
// if(iFaceTrackTimeCount&16*1000)
if(m_hProcesss!=NULL)
WaitForSingleObject(m_hProcesss,INFINITE);
CloseHandle(m_hProcesss);
m_hProcesss = NULL;
// Clean up.
pFTResult-&Release();
pColorFrame-&Release();
pFT-&Release();
NuiShutdown();
//显示网状人脸,初始化人脸模型
HRESULT VisualizeFaceModel(IFTImage* pColorImg, IFTModel* pModel, FT_CAMERA_CONFIG const* pCameraConfig, FLOAT const* pSUCoef,
FLOAT zoomFactor, POINT viewOffset, IFTResult* pAAMRlt, UINT32 color)//zoomFactor = 1.0f viewOffset = POINT(0,0) pAAMRlt为跟踪结果
if (!pColorImg || !pModel || !pCameraConfig || !pSUCoef || !pAAMRlt)
return E_POINTER;
HRESULT hr = S_OK;
UINT vertexCount = pModel-&GetVertexCount();//面部特征点的个数
FT_VECTOR2D* pPts2D = reinterpret_cast&FT_VECTOR2D*&(_malloca(sizeof(FT_VECTOR2D) * vertexCount));//二维向量 reinterpret_cast强制类型转换符 _malloca在堆栈上分配内存
//复制_malloca(sizeof(FT_VECTOR2D) * vertexCount)个字节到pPts2D,用于存放面部特征点,该步相当于初始化
if (pPts2D)
FLOAT *pAUs;
UINT auC//UINT类型在WINDOWS API中有定义,它对应于32位无符号整数
hr = pAAMRlt-&GetAUCoefficients(&pAUs, &auCount);
if (SUCCEEDED(hr))
//rotationXYZ人脸旋转角度!
FLOAT scale, rotationXYZ[3], translationXYZ[3];
hr = pAAMRlt-&Get3DPose(&scale, rotationXYZ, translationXYZ);
if (SUCCEEDED(hr))
hr = pModel-&GetProjectedShape(pCameraConfig, zoomFactor, viewOffset, pSUCoef, pModel-&GetSUCount(), pAUs, auCount,
scale, rotationXYZ, translationXYZ, pPts2D, vertexCount);
//这里获取了vertexCount个面部特征点,存放在pPts2D指针数组中
if (SUCCEEDED(hr))
POINT* p3DMdl = reinterpret_cast&POINT*&(_malloca(sizeof(POINT) * vertexCount));
if (p3DMdl)
for (UINT i = 0; i & vertexC ++i)
p3DMdl[i].x = LONG(pPts2D[i].x + 0.5f);
p3DMdl[i].y = LONG(pPts2D[i].y + 0.5f);
FT_TRIANGLE* pT
UINT triangleC
hr = pModel-&GetTriangles(&pTriangles, &triangleCount);
if (SUCCEEDED(hr))
struct EdgeHashTable
UINT32* pE
UINT edgesA
void Insert(int a, int b)
UINT32 v = (min(a, b) && 16) | max(a, b);
UINT32 index = (v + (v && 8)) * 49157,
for (i = 0; i & edgesAlloc - 1 && pEdges[(index + i) & (edgesAlloc - 1)] && v != pEdges[(index + i) & (edgesAlloc - 1)]; ++i)
pEdges[(index + i) & (edgesAlloc - 1)] =
eht.edgesAlloc = 1 && UINT(log(2.f * (1 + vertexCount + triangleCount)) / log(2.f));
eht.pEdges = reinterpret_cast&UINT32*&(_malloca(sizeof(UINT32) * eht.edgesAlloc));
if (eht.pEdges)
ZeroMemory(eht.pEdges, sizeof(UINT32) * eht.edgesAlloc);
for (UINT i = 0; i & triangleC ++i)
eht.Insert(pTriangles[i].i, pTriangles[i].j);
eht.Insert(pTriangles[i].j, pTriangles[i].k);
eht.Insert(pTriangles[i].k, pTriangles[i].i);
for (UINT i = 0; i & eht.edgesA ++i)
if(eht.pEdges[i] != 0)
pColorImg-&DrawLine(p3DMdl[eht.pEdges[i] && 16], p3DMdl[eht.pEdges[i] & 0xFFFF], color, 1);
_freea(eht.pEdges);
// 画出人脸矩形框
RECT rectF
hr = pAAMRlt-&GetFaceRect(&rectFace);//得到人脸矩形
if (SUCCEEDED(hr))
POINT leftTop = {rectFace.left, rectFace.top};//左上角
POINT rightTop = {rectFace.right - 1, rectFace.top};//右上角
POINT leftBottom = {rectFace.left, rectFace.bottom - 1};//左下角
POINT rightBottom = {rectFace.right - 1, rectFace.bottom - 1};//右下角
UINT32 nColor = 0xff00
SUCCEEDED(hr = pColorImg-&DrawLine(leftTop, rightTop, nColor, 1)) &&
SUCCEEDED(hr = pColorImg-&DrawLine(rightTop, rightBottom, nColor, 1)) &&
SUCCEEDED(hr = pColorImg-&DrawLine(rightBottom, leftBottom, nColor, 1)) &&
SUCCEEDED(hr = pColorImg-&DrawLine(leftBottom, leftTop, nColor, 1));
_freea(p3DMdl);
hr = E_OUTOFMEMORY;
_freea(pPts2D);
hr = E_OUTOFMEMORY;
获取人脸特征点三维坐标
IFTModel* ftM
hr = context-&m_pFaceTracker-&GetFaceModel(&ftModel),hR;
if(FAILED(hr))
pSU = NULL;
headScale,tempDistance=1;
context-&m_pFaceTracker-&GetShapeUnits(&headScale, &pSU, &numSU, &suConverged);
viewOffset = {0, 0};
IFTResult* pAAMRlt = context-&m_pFTR
vertexCount = ftModel-&GetVertexCount();//顶点
FT_VECTOR2D* pPts2D = reinterpret_cast&FT_VECTOR2D*&(_malloca(sizeof(FT_VECTOR2D) * vertexCount));
if ( pPts2D )
FLOAT* pAUs;
hr = pAAMRlt-&GetAUCoefficients(&pAUs, &auCount);
if (SUCCEEDED(hr))
FLOAT scale, rotationXYZ[3], translationXYZ[3];
hr = pAAMRlt-&Get3DPose(&scale, rotationXYZ, translationXYZ);
//rotationXYZ是最重要的数据!
if (SUCCEEDED(hr))
hr = ftModel-&GetProjectedShape(&m_videoConfig, 1.0, viewOffset, pSU, ftModel-&GetSUCount(), pAUs, auCount,
scale, rotationXYZ, translationXYZ, pPts2D, vertexCount);
FT_VECTOR3D* pPts3D = reinterpret_cast&FT_VECTOR3D*&(_malloca(sizeof(FT_VECTOR3D) * vertexCount));
hR = ftModel-&Get3DShape(pSU,ftModel-&GetSUCount(),pAUs,ftModel-&GetAUCount(),scale,rotationXYZ,translationXYZ,pPts3D,vertexCount);
if (SUCCEEDED(hr)&&SUCCEEDED(hR))
{。。。。。。。。。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:355198次
积分:3877
积分:3877
排名:第5498名
原创:48篇
转载:11篇
评论:489条
我的邮箱:
文章:13篇
阅读:55054
(1)(3)(2)(1)(1)(2)(1)(1)(2)(2)(8)(4)(1)(1)(4)(5)(3)(1)(5)(2)(3)(1)(3)(1)(1)(1)(2)(3)(3)

我要回帖

更多关于 xbox360 kinect更新包 的文章

 

随机推荐