安装xbox,win7设备管理器器显示安装了kinectinterface0,音频管理器里多一个输出,运行toolkit例子说没发现如图

ros中安装kinect的一个总结
ros中安装kinect的一个总结
  kinect是xbox360版本的,带一个原装电源,在淘宝上淘的。
  首先在windows下面安装,测试了一下,确认是不是好的,装的是KinectSDK-v1.0-beta2-x64微软的开发包,beta版本的,好像是说新的1.6版的不支持xbox版的kinect了,装好后,发现驱动成功了。打开开发包自带的一个测试程序Sample Skeletal Viewer,发现彩色左右两个窗口可以正常显示,中间那个显骨架的显示黑色,没的反应,以为是坏了,小紧张了一下。在网上找了一些资料也没有说清楚,再仔细分析了一下,觉得kinect放得有点近,不到一米,把它放远2米左右,这下好了,中间也有显示了,显示一个小骨架在动。
  接下来就在ubuntu下面装,ubuntu是12.04版本,ros装的是Fuerte版本,安装的命令是
  sudo apt-get install ros-fuerte-openni-camera ros-fuerte-openni-launch装好以后,运行,发现有报python错误,一查发现是这个版本的bug,没办法,只能按开源机器人操作系统这本书提到的安装ubuntu 11.04
  和ros的Diamondback版本,把驱动装好以后,运行,都正常。
  另外一点就是kinect不能在虚拟机中驱动,因为ubuntu 12.04不能装Diamondback版本,所以我在win7下面装了个虚拟机,结果还是不行。只有把原来装的12.04的版本删掉,重新装了ubuntu 11.04和Diamondback,才都正常的。
H3C认证Java认证Oracle认证
基础英语软考英语项目管理英语职场英语
.NETPowerBuilderWeb开发游戏开发Perl
二级模拟试题一级模拟试题一级考试经验四级考试资料
港口与航道工程建设工程法规及相关知识建设工程经济考试大纲矿业工程市政公用工程通信与广电工程
操作系统汇编语言计算机系统结构人工智能数据库系统微机与接口
软件测试软件外包系统分析与建模敏捷开发
法律法规历年试题软考英语网络管理员系统架构设计师信息系统监理师
高级通信工程师考试大纲设备环境综合能力
路由技术网络存储无线网络网络设备
CPMP考试prince2认证项目范围管理项目配置管理项目管理案例项目经理项目干系人管理
Powerpoint教程WPS教程
电子政务客户关系管理首席信息官办公自动化大数据
职称考试题目
就业指导签约违约职业测评
招生信息考研政治
网络安全安全设置工具使用手机安全
3DMax教程Flash教程CorelDraw教程Director教程
Dreamwaver教程HTML教程网站策划网站运营Frontpage教程
生物识别传感器物联网传输层物联网前沿技术物联网案例分析
互联网电信IT业界IT生活
Java核心技术J2ME教程
Linux系统管理Linux编程Linux安全AIX教程
Windows系统管理Windows教程Windows网络管理Windows故障
组织运营财务资本
视频播放文件压缩杀毒软件输入法微博
数据库开发Sybase数据库Informix数据库
&&&&&&&&&&&&&&&
希赛网 版权所有 & &&77840人阅读
Kinect(8)
Kinect开发学习笔记之(一)Kinect介绍和应用
一、Kinect简介
& & & Kinectfor Xbox 360,简称 Kinect,是由微软开发,应用于Xbox 360 主机的周边设备。它让玩家不需要手持或踩踏控制器,而是使用语音指令或手势来操作 Xbox360 的系统界面。它也能捕捉玩家全身上下的动作,用身体来进行游戏,带给玩家“免控制器的游戏与娱乐体验”。其在日于美国上市,建议售价149美金。Kinect在销售前60天内,卖出八百万部,目前已经申请金氏世界记录,成为全世界销售最快的消费性电子产品。
& & & &日,微软正式发布面向Windows系统的Kinect版本“Kinect for Windows”,建议售价249美金。而在2012年晚些时候,微软还将发布面向“教育用户”的特别版Kinect。(以上来自wiki百科)
& & & &Kinect有三个镜头,中间的镜头是 RGB 彩色摄影机,用来采集彩色图像。左右两边镜头则分别为红外线发射器和红外线CMOS 摄影机所构成的3D结构光深度感应器,用来采集深度数据(场景中物体到摄像头的距离)。彩色摄像头最大支持分辨率成像,红外摄像头最大支持640*480成像。Kinect还搭配了追焦技术,底座马达会随着对焦物体移动跟着转动。Kinect也内建阵列式麦克风,由四个麦克风同时收音,比对后消除杂音,并通过其采集声音进行语音识别和声源定位。
1.2、软件开发环境
1.2.1、非官方组合
& & & 一开始微软对Xbox 360推出Kinect的时候,并没有在windows的开发包。而由于Kinect强大的功能和相对低廉的价格,geeks们纷纷表示希望能在电脑上用它。于是就有多位大牛开发了驱动,目前我了解到的有三个:
1)CL NUI Platform
& & & 由NUI的大牛AlexP开发(他开发的其他著名产品包括PS3的windows驱动),可以到下载,目标平台是windows7,能够获取彩色摄像头,深度传感器以及加速度传感器数据,使用简单方便。
2)OpenKinect/libfreenect
& & & &由号称第一个破解Kinect的Hector Martin发起,可以到下载,目标平台是Linux
and Mac,据说有人成功移植到了windows上。因为很多geek都是Mac的拥趸,所以开发参与者众多,不仅仅是个可以获得数据的driver,geek们还写了其他高级的东西,比如我前面提到的骨骼化,将彩色摄像头作为纹理贴在深度数据上等等,很吸引人啊。
& & & &OpenNI(opennatural interface开放自然交互)是一个多语言,跨平台的框架,它定义了编写应用程序,并利用其自然交互的API。可以到下载。从名字判断其终极目标大约是实现少数派报告的效果,从目前放出来的一些demo,恐怕已经超越了这个终极目标。它不是专为Kinect开发,但有Kinect的生产商PrimeSense的支持。这个感觉也是目前相对来说用的比较多的非官方组合:SensorKinect
+ NITE + OpenNI;其中SensorKinect是Kinect的驱动。NITE是PrimeSense提供的中间件,可以分析Kinect读取的资料,输出人体动作等等。
1.2.2、微软官方SDK
& & & &Kinect体感游戏在Xbox 360 上获得很好的评价,但是对于 Windows 平台上的开发却一直只能使用非官方的解决方案(上面所说),例如NKinect 配合CL NUI SDK;但是微软终于在2011 年 6 月推出了 Kinect forWindows SDK Beta,特别是可以使用 C# 与.NETFramework 4.0 来进行开发。Kinect for Windows SDK主要是针对Windows7设计,内含驱动程序、丰富的原始感测数据流程式开发接口、自然用户接口、安装文件以及参考例程。Kinect
for Windows SDK可让使用C++、C#或VisualBasic语言搭配MicrosoftVisualStudio2010工具的程序设计师轻易开发使用。目前最新是V1.6 。
& & & Kinectfor Windows SDK的下载地址:
& & & &Kinect SDK目前只支持Windows 7,分为x86和x64两个版本。开发工具方面还需要.NET Framework 4.0和Visual Studio 2010 (最低Express版本)的支持。这个在后面的开发环境的配置中再做介绍。
1.2.3、非官方和官方开发包的优缺点
1)官方SDK:
& & & &提供了音频支持、调整倾角的转动电机、在全身跟踪骨骼跟踪方面:非标准姿势检测(相对于OpenNi的投降姿势…),头部、手、脚、锁骨检测以及关节遮挡等细节上的处理更为细致(但精度是否更高还不能确定)。此外,支持多传感器(多台Kinect);
& & & &微软对非商业使用的限制。此外,未提供手势识别和跟踪功能,未实现RGB图像/深度图像的互对齐,只是提供了对个体坐标系的对齐。在全身骨骼跟踪中,SDK只计算了关节的位置,并未得出其旋转角度。从可移植的角度来看,SDK beta只能用于Kinect/Win7平台,而OpenNi还至少支持华硕的WAVI Xtion体感设备,今后支持的硬件平台还可能更多。相比较而言SDK beta不支持Unity3D游戏引擎、不支持记录/回放数据写入磁盘、不支持原始红外视频数据流、也不支持像OpenNi一样的角色入场和出场的事件响应机制。
2)非官方OpenNI/NITE:
& & & &可用于商业开发、包含手势识别和跟踪功能、可自动对齐深度图像和RGB图像,全身跟踪、关节旋转角度计算、看起来性能较好、已有众多游戏产品应用、支持记录/回放数据写入磁盘、支持原始红外视频数据流、支持角色入场和出场的事件响应机制。支持Primesense和华硕的WAVI Xtion硬件平台和windows、Linux和Mac等软件平台。自带的代码全面支持Unity3D游戏引擎。
& & & &未提供音频功能、不支持调整倾角的转动电机、在全身跟踪骨骼跟踪方面:无法跟踪头部、手、脚和锁骨的旋转动作,需要标准姿势检测(即著名的投降姿势…),关节遮挡等细节上的处理似乎存在算法bug。不能自动安装并识别Kinect多机环境。安装过程较为繁琐,特别是NITE还要申请开发证书编码。OpenNi也没有提供可用视频和深度图输入的事件触发机制(但OpenNI提供了类似功能的函数可使用,虽然不是回调函数,但是也很好用)。
& & & &OpenNI最大的优势就是允许跨平台多设备,以及商业应用。但从原始数据的采集和预处理技术上看,微软的SDK似乎更稳定一些,况且还提供了不错的骨骼和语音支持。对于部分身体部位识别方面的功能,SDKbeta没有提供局部识别和跟踪,这需要自己的后续开发(至少在相当一段时期内微软可能都不会提供此类功能)。OpenNi/NITE虽然提供了手势识别和跟踪,然而在全身骨骼姿势识别和跟踪上还要更多借鉴微软的产品。
因此,按照目前在社区中的表现,SDK beta和OpenNi/NITE孰优孰劣还真无法一下子确定。而且随着越来越多的开发者加入微软这一方,SDK beta的普及可能会更快,但在更高层次的应用上,对二者的选用往往是需要一定智慧的。
(这部分参考:)
二、Kinect应用开发汇总
& & & 本文(百度文库上面的内容,来源未知)汇总了当前使用Kinect SDK for Windows 开发出的各种各样的应用,点击相应的链接可以看到对应Kinect应用的Demo视频。
Kinect试衣镜,这款基于kinect体感技术的神奇的试衣镜,让客户可以快速的试穿衣服,提高销售效率和企业形象。
Kinect自制应用3D试衣间
3D摄像机,&用两个KINECT实现3D摄像机的基本效果。
雕塑工具,立等可取Kinect成街头快速人像雕塑工具,利用Kinect对人体进行3D建模,然后根据人体的3D信息,连接相应的塑模设备,塑造出人体塑像。
用Kinect 操控遥控直升机&
Kinect Robo,使用Kinect作为机器人的头,通过kinect检测周围环境,并进行3D建模,来指导机器人的行动。
Kinect控制高达机械人
空气吉他,通过Kinect手势操作虚拟吉他弹奏音乐。
Kinect弹奏中国古代乐器,通过手势的改变可以演奏出不同中国古代乐器的声音。
Kinect破解“初音”,将体感控制应用到漫画人物——初音上。
变身奥特曼,捕捉玩家骨架数据,虚拟为奥特曼的形态与之随动,并且附加一些特技效果。
Kinect破解玩光剑,Kinect检测玩家的动作,虚拟出光剑的影像,与之随动。
计算机相关应用
Kinect手势操作浏览器,通过Kinect手势对浏览器进行翻页,下拉,放缩等操作。
Air Presenter,让你的演讲从此与众不同,用kinect进行演讲的软件。
Kinect多点触摸,使用kinect实现隔空多点触摸,浏览图片、地图等。
Kinect体感控制看片,第四军医大学西京医院骨科的医生们将破解的kinect应用在手术室,在术中,手术者可通过体感控制查看患者的影像资料。大大方便了医生手术,减少了手术室的人员流动。
Kinect蜡笔物理,使用Kinect手势绘图,通过体感控制所绘图形,并使之具有物理特性,比如重力,吸引力等。
用Kinect控制闪电(特斯拉线圈)
Kinect破解玩马克思佩恩
kinect破解玩求生之旅2 体感打僵尸
Kinect破解玩魔兽世界&&&
Kinect破解玩街头霸王&&&
Kinect破解玩超级马里奥兄弟&
Kinect破解玩兵者诡道&&&
Kinect破解玩 现代战争&&
& & & &一群来自卡内基梅隆的学生使用Kinect的交互特点实现了18个各种各种的有趣的想法。他们仅仅用了两周的时间,从大二学生到研究生不等。让我们来看一下他们实现的奇思妙想吧!
& & & &原文及视频信息链接
1. Comic Kinect
& & & 此示例主要应用了Kinect的骨架跟踪技术和玩家分段数据,将拳击和脚踢的交互通过可视的漫画效果表现出来,并且同步发出一些拟声效果。
2. Mario Boo
& & & &当Kinect传感器检测到有人出现在视野内时,会出现一个幽灵保持在人的背后,随着人的运动而运动,并且会根据深度信息的远近而改变自身大小。
3. Magrathea
& & & &Magrathea使用Kinect根据桌上的任何物体动态的产生地形图。摄像头读取桌上物体的不断变化深度信息,可以展现出类似地球地形逐渐进化的过程。
4. We be Monsters
& & & &从中午舞狮中获取灵感,运用Kinect的骨架跟踪技术,两个人分别同坐自己的四肢操纵虚拟怪兽的四肢和头尾。
5. Mix&Match Interaction Toy
& & & &使用了Kinect/OpenNI 骨架技术,使得3张卡片组成的人体可以跟玩家随动,并且通过手的滑动更换图片。
6. Kinect Flock
& & & &作者创建了一个微粒系统,当用户移动时,像棉絮一样的东西会随之涌动,当用户静止时,则聚集到参与者的深度区域。
7. roboScan
& & & &roboScan是一个3D模型+扫描仪,将一个Kinect设备固定在一个ABB 4400机械手上。设定好的动作和操作者同时控制机器人和摄像机的3D位置。Kinect的深度数据用来产生一个精确的外部环境的模型。
8. Neurospasta
& & & & Neurospasta是一个需要全身投入的自由形态游戏平台。参与者可以控制他们各自基于Kinect的木偶,也可以通过功能设定控制别人的化身。
9. Will-o-the-Wisp
& & & 这个设计充满了神秘色彩,玩家可以控制一个发光的球体,球体根据玩家手的运动而动,根据深度信息变大或变小。
10. Balloon Grab
& & & &通过检测手掌张开还是握紧的手势,作者开发了一个基于模拟气球飞行的简易小游戏。
11. Hand-Tracking Visualization
& & & &该软件使用手势控制音频的可视化效果,结合检测到场景中手距Kinect的深度信息。参与者手的位置,速度以及其他参数被用来创建一个交互式的声音的可视化效果。
& & & & 感觉Kinect的应用也应景一句话:Kinect的应用取决于你的想象空间!
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:5261791次
积分:25346
积分:25346
排名:第163名
原创:116篇
转载:11篇
评论:3291条
关注:机器学习、计算机视觉、人机交互和人工智能等领域。
交流请发邮件,不怎么看博客私信^-^
(4)(2)(1)(1)(2)(2)(1)(7)(5)(4)(4)(9)(2)(6)(1)(10)(5)(8)(14)(7)(8)(25)kinect2.0 首次安装自动下载驱动没反应。xbox nui sensor感叹号_百度知道
kinect2.0 首次安装自动下载驱动没反应。xbox nui sensor感叹号
jpg" esrc="http.hiphotos,如图,本来之前一台电脑上插上之后会自动识别然后下载驱动./zhidao/wh%3D450%2C600/sign=d388d43ff0fc99f6482efe2d/dddea2efce1b9d166126。但是这台新电脑第一步都过不去.baidu,一两个小时都没反应.baidu.jpg" esrc="http,我要不点掉这个窗口请各位大神帮帮忙./zhidao/wh%3D600%2C800/sign=/zhidao/pic//zhidao/wh%3D450%2C600/sign=70fbaa1ba794fbfeed12f2eb83894a3:///zhidao/pic/item/dddea2efce1b9d166126.jpg" />就一直显示.hiphotos。打开设备管理器就有一个新的感叹号.jpg" target="_blank" title="点击查看大图" class="ikqb_img_alink"><img class="ikqb_img" src="http.baidu.hiphotos,再然后安装sdk就可以用了.baidu
您的回答被采纳后将获得:
系统奖励20(财富值+经验值)+难题奖励10(财富值+经验值)+提问者悬赏25(财富值+经验值)
我有更好的答案
我也是同样的问题。请问您解决吗
其他类似问题
为您推荐:
xbox的相关知识
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁posts - 8,&
comments - 74,&
trackbacks - 0
&&&& 个人理解错误的地方还请不吝赐教,转载请标明出处,内容如有改动更新,请看原博:
& & &如有任何问题,feel free to contact me at&
&&&& 最近经常有朋友问到Kinect V2在Ubuntu下的开发问题,首先需要弄清楚的是你的设备是V1还是V2,这两个的驱动是不能通用的。
如下是V2(左)和V1(右)。看看自己的设备,然后再决定用哪个安装方案。
& & &本文针对的是V2的情况。
1、首先git下载代码,很快下载好,放到~下面
git clone /OpenKinect/libfreenect2.git
2、然后安装依赖项如下,最好事先编译安装好OpenCV
sudo apt-get install build-essential cmake pkg-config libturbojpeg libjpeg-turbo8-dev mesa-common-dev freeglut3-dev libxrandr-dev libxi-dev
3、然后安装libusb。此处需要添加一个PPA,就是下面的第一行命令,不然绝逼是装不上的。
sudo apt-add-repository ppa:floe/libusb
sudo apt-get update
sudo apt-get install libusb-1.0-0-dev
4、接着运行下面的命令,安装GLFW3
sudo apt-get install libglfw3-dev
如果没有成功的话,使用下面的命令,来代替上面的
cd libfreenect2/depends
sh install_ubuntu.sh
sudo dpkg -i libglfw3*_3.0.4-1_*.deb
5、然后安装OpenCL的支持库(不打算使用GPU,这一步直接跳过没做)
6、接着编译库
mkdir build && cd build
sudo make install
最后可以运行程序.
在build下面有个bin文件夹,放置生成的输出文件,插上kinect,然后运行。此时黄灯变成白色的,表示有驱动。注意:只能用于USB3的接口,好在台式机和笔记本都有3.0的口。
./bin/Protonect
但是提示权限不够,failed to open Kinect V2 Access denied
此时需要把libfreenect2文件夹下面的rules里面的一个90开头的文件复制到/etc/udev/rules.d/下面就可以了。
然后重新运行上面的命令就可以了。
Ros接口安装
对于已经安装了Ros Indigo的Ubuntu14.04来说,使用下面的命令
cd ~/catkin_ws/src/
git clone /code-iai/iai_kinect2.git
cd iai_kinect2
rosdep install -r --from-paths .
cd ~/catkin_ws
catkin_make -DCMAKE_BUILD_TYPE="Release"
rospack profile
  接下来可以测试了。
roslaunch kinect2_bridge kinect2_bridge.launch
  然后重新开一个新的终端
rosrun kinect2_viewer kinect2_viewer
  显示如下图所示。Good Luck and enjoy it!
阅读(...) 评论()7857人阅读
Kinect(15)
//****************Edit 02/08/2015*******************************
在KinectSDK2.0发布后,好多人反应找不到KinectSDK 1.8的下载页面,现将链接粘在此处&
Kinect MSDN Blog——关于Kinect最新官方新闻
//******************************************************************
Kinect SDK&读取彩色、深度、骨骼信息并用OpenCV显示
一、原理说明
对于原理相信大家都明白大致的情况,因此,在此只说比较特别的部分。
1.1 深度流数据:
深度数据流所提供的图像帧中,每一个像素点代表的是在深度感应器的视野中,该特定的(x, y)坐标处物体到离摄像头平面最近的物体到该平面的距离,
注意是平面到平面距离,并不是到摄像机的斜线距离(以毫米为单位)。
Kinect中深度&#20540;最大为4096mm,0&#20540;通常表示深度&#20540;不能确定,一般应该将0&#20540;过滤掉。微软建议在开发中使用1220mm~3810mm范围内的&#20540;。
在进行其他深度图像处理之前,应该使用阈&#20540;方法过滤深度数据至1220mm-3810mm这一范围内。
下图显示了Kinect Sensor的感知范围,其中的default range对Xbox
360和Kinect for Windows都适用,而near range仅对后者适用:
深度数据的存储:
Kinect的深度图像数据含有两种&#26684;式,两种&#26684;式都是用两个字节来保存一个像素的深度&#20540;,而两方式的差别在于:
(1)唯一表示深度&#20540;:那么像素的低12位表示一个深度&#20540;,高4位未使用;
(2)既表示深度&#20540;又含有游戏者ID:Kinect SDK具有分析深度数据和探测人体或者游戏者轮廓的功能,它一次能够识别多达6个游戏者。SDK为每一个追踪到的游戏者编号作为索引。
而这个方式中,像素&#20540;的高13位保存了深度&#20540;,低三位保存用户序号,7 ()这个位掩码能够帮助我们从深度数据中获取到游戏者索引&#20540;。对于这种情况的处理如下:
USHORTrealDepth = (depthID & 0xfff8) && 3; //提取距离信息,高13位
USHORTplayer =& depthID & 0x07 ;& //提取ID信息,低3位
SDK提供了专门的函数:
SHORT realDepth= NuiDepthPixelToDepth(depth);
USHORT playerIndex & & & &&= NuiDepthPixelToPlayerIndex(depth);//获得深度图该点像素位置对应的 UserID;
在对OpenCV进行赋&#20540;时需要将其转化到[0,255]
BYTE b = 255 - static_cast&BYTE&(256 * realDepth / 0x0fff);
1.2 Skeleton信息
玩家的各关节点位置用(x, y,&z)坐标表示。与深度图像空间坐标不同的是,这些坐标单位是米。坐标轴x,y, z是深度感应器实体的空间x, y, z坐标轴。这个坐标系是右手螺旋的,Kinect感应器处于原点上,z坐标轴则与Kinect感应的朝向一致。y轴正半轴向上延伸,x轴正半轴(从Kinect感应器的视角来看)向左延伸,如下图所示。
Kinect放置的位置会影响生成的图像。例如,Kinect可能被放置在非水平的表面上或者有可能在垂直方向上进行了旋转调整来优化视野范围。在这种情况下,y轴就往往不是相对地面垂直的,或者不与重力方向平行。最终得到的图像中,尽管人笔直地站立,在图像中也会显示出事倾斜的。
Kinect最多可以跟踪两个骨骼,可以最多检测六个人。站立模式可以跟踪20个关节点,坐姿模式的话,可以跟踪10个关节点。
& & & &NUI骨骼跟踪分主动和被动两种模式,提供最多两副完整的骨骼跟踪数据。主动模式下需要调用相关帧读取函数获得用户骨骼数据,而被动模式下还支持额外最多四人的骨骼跟踪,但是在该模式下仅包含了用户的位置信息,不包括详细的骨骼数据。也就是说,假如Kinect面前站着六个人,Kinect能告诉你这六个人具体站在什么位置,但只能提供其中两个人的关节点的数据(这两个人属于主动模式),也就是他们的手啊,头啊等等的位置都能告诉你,而其他的人,Kinect只能提供位置信息,也就是你站在哪,Kinect告诉你,但是你的手啊,头啊等具体在什么位置,它就没法告诉你了(这四个人属于被动模式)。
对于所有获取的骨骼数据,其至少包含以下信息:
1)、相关骨骼的跟踪状态,被动模式时仅包括位置数据(用户所在位置),主动模式包括完整的骨骼数据(用户20个关节点的空间位置信息)。
2)、唯一的骨骼跟踪ID,用于分配给视野中的每个用户(和之前说的深度数据中的ID是一个东西,用以区分现在这个骨骼数据是哪个用户的)。
3)、用户质心位置,该&#20540;仅在被动模式下可用(就是标示用户所在位置的,当无法检测出Skeleton数据时,就应该显示用户质心位置,因为质心是根据深度图的UserID计算出来的,并不受骨骼信息影响)。
二、流程解析
作为一名KINECT程序员,你需要记得的是,微软SDK中提供的运行环境在处理KINECT传输数据时,是遵循一条3步骤的运行管线的。
第一阶段:只处理彩色和深度数据
第二阶段:处理用户索引并根据用户索引将颜色信息追加到深度图中。(参考 NUI_INITIALIZE_FLAG_USES_DEPTH_AND_PLAYER_INDEX)
第三阶段:处理骨骼追踪数据
1. 基本设置
1.1 在vs2010项目中,需要设置C&#43;&#43;目录
包含目录中加入 $(KINECTSDK10_DIR)\
库目录中加入 & &$(KINECTSDK10_DIR)\lib\x86
& &(注意安装Kinect SDK以后,路径不一样了,环境变量名变成KINECTSDK10_DIR)
& &MSRKINECTSDK是环境变量,正确安装MS KINECT FRO WINDOWS SDK 后,会在计算机中的环境变量中看到。
1.2 添加特定库
& &除了指定目录外,你还需要在链接器中设置附加依赖项,填入KinectNUI.lib
1.3 头文件
为了使用NUI中的API,首先我们要包含 NuiApi.h,切记,在这之前,要保证你已经包含了windows.h
& &#include &Windows.h&
& &&#include &NuiApi.h&
& &切记,在这之前,要保证你已经包含了windows.h否则 Nuiapi中很多根据windows平台定义的数据类型及宏都不生效。
1.4 其他设置
如果要使用Kinect SDK 1.7&#43;中的Inteaction部分控件,除了以上提到的基本设置需要额外加入Kinect toolkit文件夹下的相应的.h、.lib以及dll文件。
其实最简单的方法就是把Kinect Toolkits中的类&#20284;sample Install到目录,一看就知道怎么做的了、
2. Nui初始化
接下来,任何想使用微软提供的API来操作KINECT,都必须在所有操作之前,调用NUI的初始化函数
HRESULT NuiInitialize(DWORD dwFlags);
DWORD dwFlags参数:
NUI_INITIALIZE_FLAG_USES_DEPTH_AND_PLAYER_INDEX& &&使用NUI中的带用户信息的深度图数据
NUI_INITIALIZE_FLAG_USES_COLOR & & & & & & & & & & & & & & & & & & & &使用NUI中的彩色图数据
NUI_INITIALIZE_FLAG_USES_SKELETON & & & & & & & & & & & & & & & & &使用NUI中的骨骼追踪数据
NUI_INITIALIZE_FLAG_USES_DEPTH & & & & & & & & & & & & & & & & & & & &仅仅使用深度图数据(如果你自己有良好的场景分析或物体识别算法,那么你应该用这个)
以上4个标志位,你可以使用一个,也可以用 | 操作符将它们组合在一起。例如:
HRESULT hr = NuiInitialize(NUI_INITIALIZE_FLAG_USES_COLOR);//只使用彩色图
HRESULT hr = NuiInitialize(NUI_INITIALIZE_FLAG_USES_DEPTH_AND_PLAYER_INDEX | NUI_INITIALIZE_FLAG_USES_SKELETON | NUI_INITIALIZE_FLAG_USES_COLOR);//使用带用户信息的深度图/使用用户骨骼框架/使用彩色图
NuiInitialize就是应用程序用通过传递给dwFlags参数具体&#20540;,来初始化Kinect
SDK处理管线中必须的阶段。因此,我们总是先在标志位中指定图像类型,才可以在接下来的环节中去调用NuiImageStreamOpen之类的函数。如果你初始化的时候没指定NUI_INITIALIZE_FLAG_USES_COLOR,那你以后就别指望NuiImageStreamOpen能打开彩色数据了,它肯定会调用失败,因为没初始化嘛。
初始化以后,在我们继续其他深入获取NUI设备的数据之前,先了解一下如何关闭你的程序与NUI之间的联系。
VOID NuiShutdown();
关于这个函数,没什么可说的,你的程序退出时,都应该调用一下。甚至于,你的程序暂时不使用KINECT了,就放开对设备的控制权,好让其他程序可以访问KINECT。
友情提示使用OpenGL的程序员们,如果你们是在使用glut库,那么不要在glMainLoop()后面调用NuiShutdown(),因为它不会执行,你应该在窗口关闭以及任意你执行了退出代码的时刻调用它。
一个应用程序对一个KINECT设备,必须要调用此函数一次,并且也只能调用一次。如果在这之后又调用一次初始化,势必会引起逻辑错误(即使是2个不同程序)。比如你运行一个SDK的例子,在没关闭它的前提下,再运行一个,那么后运行的就无法初始化成功,但不会影响之前的程序继续运行。
如果你的程序想使用多台KINECT,那么请使用INuiInstance接口来初始化你的设备。
3. CreateNextFrame&Event(是否读取下一帧的控制信号)
一个用来手动重置信号是否可用的事件句柄(event),该信号用来控制KINECT是否可以开始读取下一帧数据。
HANDLE m_hNextVideoFrameEvent & = CreateEvent( NULL, TRUE, FALSE, NULL );
HANDLE m_hNextDepthFrameEvent &= CreateEvent( NULL, TRUE, FALSE, NULL );
HANDLE m_hNextSkeletonEvent & & & &= CreateEvent( NULL, TRUE, FALSE, NULL );&
HANDLE m_hEvNuiProcessStop & & & &&= CreateEvent(NULL,TRUE,FALSE,NULL);//用于结束的事件对象;&
也就是说在这里指定一个句柄后,随着程序往后继续推进,当你在任何时候想要控制kinect读取下一帧数据时,
都应该先使用WaitForSingleObject(handleEvent, 0)判断一下该句柄,是否有数据可拿。
CreateEvent()创建一个windows事件对象,创建成功则返回事件的句柄。事件有两个状态,有信号和没有信号!上面说到了。就是拿来等待新数据的。
CreateEvent函数需要4个参数:
设定为NULL的安全描述符;
一个设定为true的布尔&#20540;,因为应用程序将重置事件消息;
一个未指定的事件消息初始状态的布尔&#20540;;
一个空字符串,因为事件未命名
4. Open Stream(For color & depth stream)
打开对NUI设备的访问通道,只针对彩色数据流和深度数据流。
使用这个函数来打开kinect彩色或者深度图的访问通道,当然,其内部原理是通过&流&来实现的,因此,你也可以把这个函数理解为,创建一个访问彩色或者深度图的数据流。&#20284;乎从很久远的时候开始,微软就在windows中开始使用流来访问所有硬件设备了。
NuiImageStreamOpen (NUI_IMAGE_TYPE eImageType,&
NUI_IMAGE_RESOLUTION eResolution,
DWORD dwImageFrameFlags_NotUsed,
DWORD dwFrameLimit,
HANDLE hNextFrameEvent,
HANDLE *phStreamHandle);
NUI_IMAGE_TYPE eImageType [in]
这是一个NUI_IMAGE_TYPE
枚举类型的&#20540;(对应NuiInitialize中的标志位),用来详细指定你要创建的流类型。比如你要打开彩色图,就使用NUI_IMAGE_TYPE_COLOR。
要打开深度图,就使用
NUI_IMAGE_TYPE_DEPTH,
NUI_IMAGE_TYPE_DEPTH_AND_PLAYER_INDEX。能打开的图像类型,必须是你在初始化的时候指定过的。
NUI_IMAGE_RESOLUTION eResolution[in]
这是一个NUI_IMAGE_RESOLUTION 枚举类型的&#20540;,用来指定你要以什么分辨率来打开eImageType(参数1)中指定的图像类别。
彩色图NUI_IMAGE_TYPE_COLOR,支持2种分辨率:NUI_IMAGE_RESOLUTION_,NUI_IMAGE_RESOLUTION_640x480
深度图NUI_IMAGE_TYPE_DEPTH,支持3种分辨率:NUI_IMAGE_RESOLUTION_640x480,
NUI_IMAGE_RESOLUTION_320x240, NUI_IMAGE_RESOLUTION_80x60
DWORD dwImageFrameFlags_NotUsed [in]&
一点用没有,你随便给个整数就行了。以后的版本里不知道它会不会有意义。
DWORD dwFrameLimit[in]
指定NUI运行时环境将要为你所打开的图像类型建立几个缓冲。最大&#20540;是NUI_IMAGE_STREAM_FRAME_LIMIT_MAXIMUM(当前版本为
4).对于大多数啊程序来说,2就足够了。
HANDLE hNextFrameEvent [in, optional]&
就是之前建立的一个用来手动重置信号是否可用的事件句柄(event),该信号用来控制KINECT是否可以开始读取下一帧数据。
也就是说在这里指定一个句柄后,随着程序往后继续推进,当你在任何时候想要控制kinect读取下一帧数据时,都应该先使用WaitForSingleObject判断一下该句柄。
HANDLE phStreamHandle[out]&(就是通过这个读取数据)
指定一个句柄的地址。函数成功执行后,将会创建对应的数据访问通道(流),并且让该句柄保存这个通道的地址。也就是说,如果现在创建成功了。
那么以后你想读取数据,就要通过这个句柄了。
5. Skeleton Flag Enable(For skeleton stream)
设置Skeleton Stream跟踪标志位
HRESULTNuiSkeletonTrackingEnable(
m_hNextSkeletonEvent,&Flag );
近景:&NUI_SKELETON_TRACKING_FLAG_ENABLE_IN_NEAR_RANGE
坐姿:&NUI_SKELETON_TRACKING_FLAG_ENABLE_SEATED_SUPPORT;&
& & &&只有头肩手臂10个节点;
站姿:flag&~(NUI_SKELETON_TRACKING_FLAG_ENABLE_SEATED_SUPPORT);&&有标准的20个节点;
默认&#20540;0:站姿和非近景数据位分布如上图。
6.等待新的数据,等到后触发
WaitForSingleObject(nextColorFrameEvent, INFINITE)==0&&&&
WAIT_OBJECT_0&==&WaitForSingleObject(m_hEvNuiProcessStop,&0)
WAIT_OBJECT_0&==&WaitForSingleObject(m_hNextVideoFrameEvent,&0)
WAIT_OBJECT_0&==&WaitForSingleObject(m_hNextDepthFrameEvent,&0)
WAIT_OBJECT_0&==&WaitForSingleObject(m_hNextSkeletonEvent,&0)
程序运行堵塞在这里,这个事件有信号,就是说有数据,那么程序往下执行,如果没有数据,就会等待。函数第二个参数表示你愿意等多久,具体的数据的话就表示你愿意等多少毫秒,还不来,我就不要了,继续往下走。如果是INFINITE的话,就表示无限等待新数据,直到海枯石烂,一定等到为止。等到有信号后就返回0 。
7. 从流数据获得Frame数据
7.1 For Color & Depth Sream
7.1.1&NuiImageStreamGetNextFrame
HRESULT NuiImageStreamGetNextFrame (HANDLE hStream,
DWORD dwMillisecondsToWait,
CONST NUI_IMAGE_FRAME **ppcImageFrame);
const&NUI_IMAGE_FRAME&*&pImageFrame&=&NULL;
HRESULT&hr&=&NuiImageStreamGetNextFrame(&h,&0,&&pImageFrame&);&
HANDLE&hStream&[in]
前面NuiImageStreamOpen打开数据流时的输出参数,就是流句柄,彩色数据对应彩色流句柄,深度数据对应深度流句柄。
DWORD&dwMillisecondsToWait&[in]
延迟时间,以微秒为单位的整数。当运行环境在读取之前,会先等待这个时间。
CONST NUI_IMAGE_FRAME **ppcImageFrame&[out]
指定一个 NUI_IMAGE_FRAME 结构的指针,当读取成功后,该函数会将读取到的数据地址返回,保存在此参数中。pImageFrame包含了很多有用信息,包括:图像类型,分辨率,图像缓冲区,时间戳等等。
返回&#20540;
同样是S_OK表示成功
7.1.2&INuiFrameTexture接口
INuiFrameTexture * pTexture = pImageFrame-&pFrameT
一个容纳图像帧数据的对象,类&#20284;于Direct3D纹理,但是只有一层(不支持mip-maping)。
其公有方法包含以下:
AddRef---增加一个对象上接口的引用数目;该方法在每复制一个指向该对象上接口的指针时都要调用一次;
BufferLen---获得缓冲区的字节长度;
GetLevelDesc---获得缓冲区的描述;
LockRect---给缓冲区上锁;
Pitch---返回一行的字节数;
QueryInterface---获取指向对象所支持的接口的指针,该方法对其所返回的指针调用AddRef函数;
Release---减少一个对象上接口的引用计数;
UnlockRect---对缓冲区解锁;
7.1.3&提取数据帧到LockedRect并锁定数据
pTexture-&LockRect(0, &LockedRect, NULL, 0);
提取数据帧到LockedRect,它包括两个数据对象:pitch每行字节数,pBits第一个字节地址。另外,其还锁定数据,这样当我们读数据的时候,kinect就不会去修改它。
好了,现在真正保存图像的对象LockedRect我们已经有了,并且也将图像信息写入这个对象了。
7.1.4 将数据转换为OpenCV的Mat&#26684;式
然后将其保存图像的对象LockedRect的&#26684;式,转化为OpenCV的Mat&#26684;式。
BYTE*&pBuffer
=&(BYTE*)&LockedRect.pB
colorImg(COLOR_HIGHT,COLOR_WIDTH,CV_8UC4,pBuffer);
&Mat&depthImg(DEPTH_HIGHT,DEPTH_WIDTH,CV_16U,pBuffer);&
对于INuiFrameTexture * pTexture = pImageFrame-&pFrameT获得的数据彩色数据和深度数据的规&#26684;是不一样的!!!
彩色数据:单位数据是32位,对应BGRA
深度数据:单位数据是16位。
深度数据的取&#20540;还有另一种方式:
INuiFrameTexture* pDepthImagePixelF
BOOL nearMode = TRUE;
m_pNuiSensor-&NuiImageFrameGetDepthImagePixelFrameTexture(m_pDepthStreamHandle, &pImageFrame, &nearMode, &pDepthImagePixelFrame);
INuiFrameTexture * pTexture = pDepthImagePixelF
NUI_LOCKED_RECT LockedR
pTexture-&LockRect(0, &LockedRect, NULL, 0 );
通过这种方式获得的深度数据跟彩色数据的规&#26684;一致都是32bit一组,但是16~35位为空,不包含数据,数据依然保存在低16位,只不过加了两个通道。
7.2 For Skeleton Stream
HRESULT&NuiSkeletonGetNextFrame(
DWORD dwMillisecondsToWait,
NUI_SKELETON_FRAME&*SkeletonFrame);
NUI_SKELETON_FRAME&SkeletonF
HRESULT&hr&=&NuiSkeletonGetNextFrame(&0,&&SkeletonFrame&);&
在获得了&Depth Sream的Frame的数据之后,才能获得skeleton数据。这属于三步走管线的第三步。
骨骼帧数据保存在NUI_SKELETON_FRAME结构体中,我们首先来分析下这个最重要的结构体:
typedef struct _NUI_SKELETON_FRAME {
&&&LARGE_INTEGER liTimeS
&&&DWORD dwFrameN
&&&DWORD dwF&//没用到
&&&Vector4 vFloorClipP
&&&Vector4 vNormalToG
&&&NUI_SKELETON_DATA SkeletonData[NUI_SKELETON_COUNT];
} NUI_SKELETON_FRAME;
LARGE_INTEGER liTimeStamp &&DWORD dwFrameNumber (时间标记字段):
& & & SkeletonFrame的dwFrameNumber和liTimestamp字段表示当前记录中的帧序列信息。FrameNumber是深度数据帧中的用来产生骨骼数据帧的帧编号。帧编号通常是不连续的,但是之后的帧编号一定比之前的要大。骨骼追踪引擎在追踪过程中可能会忽略某一帧深度数据,这跟应用程序的性能和每秒产生的帧数有关。例如,在基于事件获取骨骼帧信息中,如果事件中处理帧数据的时间过长就会导致这一帧数据还没有处理完就产生了新的数据,那么这些新的数据就有可能被忽略了。如果采用查询模型获取帧数据,那么取决于应用程序设置的骨骼引擎产生数据的频率,即取决于深度影像数据产生骨骼数据的频率。
& & & &Timestap字段记录自Kinect传感器初始化(调用NuiInitialize函数)以来经过的累计毫秒时间。不用担心FrameNumber或者Timestamp字段会超出上限。FrameNumber是一个32位的整型,Timestamp是64位整型。如果应用程序以每秒30帧的速度产生数据,应用程序需要运行2.25年才会达到FrameNumber的限,此时Timestamp离上限还很远。另外在Kinect传感器每一次初始化时,这两个字段都会初始化为0。可以认为FrameNumber和Timestamp这两个&#20540;是唯一的。
& & & &这两个字段在分析处理帧序列数据时很重要,比如进行关节点&#20540;的平滑,手势识别操作等。在多数情况下,我们通常会处理帧时间序列数据,这两个字段就显得很有用。目前SDK中并没有包含手势识别引擎。在未来SDK中加入手势引擎之前,我们需要自己编写算法来对帧时间序列进行处理来识别手势,这样就会大量依赖这两个字段。
&NUI_SKELETON_DATA SkeletonData[NUI_SKELETON_COUNT]&骨骼数据段:
& & & &最重要的要数这个成员了。首先,Kinect可以检测到6个骨骼,在NuiSensor.h中有宏定义:#define&&& NUI_SKELETON_COUNT& ( 6 )。所以SkeletonData[NUI_SKELETON_COUNT]定义了六个骨骼的数据。骨骼数据是通过一个NUI_SKELETON_DATA类型的结构体保存的:
typedef struct _NUI_SKELETON_DATA {
&&&NUI_SKELETON_TRACKING_STATE eTrackingS
&&&DWORD dwTrackingID;
&&&DWORD dwEnrollmentI
&&& DWORDdwUserI
&&&Vector4 P
&&&Vector4 SkeletonPositions[20];
&&&NUI_SKELETON_POSITION_TRACKING_STATE eSkeletonPositionTrackingState[20];
&&&DWORD dwQualityF
} NUI_SKELETON_DATA;
eTrackingState:
eTrackingState字段表示当前的骨骼数据的状态,是一个枚举类型。
typedef enum NUI_SKELETON_TRACKING_STATE
&&&NUI_SKELETON_NOT_TRACKED = 0,
&&&NUI_SKELETON_POSITION_ONLY,
&&&NUI_SKELETON_TRACKED
} NUI_SKELETON_TRACKING_STATE;
下表展示了SkeletonTrackingState枚举的可能&#20540;的含义:
NUI_SKELETON_NOT_TRACKED&& 表示骨架没有被跟踪到,这个状态下,骨骼数据的Position字段和相关的关节点数据中的每一个位置点&#20540;都是0 。
NUI_SKELETON_POSITION_ONLY&& 检测到了骨骼对象,但是跟踪没有激活,也就是说骨骼数据的Position字段有&#20540;,但是相关的关节点数据中的每一个位置点&#20540;都是0(对应被动模式,被动模式只提供骨骼的位置,不提供关节点的位置)。
NUI_SKELETON_TRACKED&& 所有骨骼点的位置都被跟踪,骨骼数据的Position字段和相关的关节点数据中的每一个位置点&#20540;都非零(对应主动模式,骨骼位置和关节点位置都提供)。
dwTrackingID:
& & & 骨骼追踪引擎对于每一个追踪到的游戏者的骨骼信息都有一个唯一编号。这个&#20540;是整型,他会随着新的追踪到的游戏者的产生添加增长。另外,这个编号的产生是不确定的。如果骨骼追踪引擎失去了对游戏者的追踪,比如说游戏者离开了Kinect的视野,那么这个对应的唯一编号就会过期。当Kinect追踪到了一个新的游戏者,他会为其分配一个新的唯一编号。编号&#20540;为0表示这个骨骼信息不是游戏者的。
Position:
& & &Position是一个Vector4类型的字段,代表所有骨骼的中间点。身体的中间点和脊柱关节的位置相当。该字段提供了一个最快且最简单的所有视野范围内的游戏者位置的信息,而不管其是否在追踪状态中。在一些应用中,如果不用关心骨骼中具体的关节点的位置信息,那么该字段对于确定游戏者的位置状态已经足够。该字段对于手动选择要追踪的游戏者也是一个参考。例如,应用程序可能需要追踪距离Kinect最近的且处于追踪状态的游戏者,那么该字段就可以用来过滤掉其他的游戏者。
Vector4类型是一个空间坐标的类型:
Vector4typedef struct _Vector4 {
&&&FLOAT& //X coordinate
&&&FLOAT& //Y coordinate
&&&FLOAT& //Z coordinate
&&&FLOAT& //W coordinate
} Vector4;
SkeletonPositions[20]:
& & & &这个数组记录的是主动模式下骨骼的20个关节点对应的空间位置信息。每一个关节点都有类型为Vector4的位置属性,他通过X,Y,Z三个&#20540;来描述关节点的位置。X,Y&#20540;是相对于骨骼平面空间的位置,他和深度影像,彩色影像的空间坐标系不一样。KinectSnesor对象有一系列的坐标转换方法,可以将骨骼坐标点转换到对应的深度数据影像中去。
SkeletonPositionTrackingState[20]:
& & & &上面说到骨骼有跟踪的好与不好,那么关节点也是跟踪和分析的,那也有好与不好之分吧。而SkeletonPositionTrackingState属性就是标示对应的每一个关节点的跟踪状态的:
typedef enum _NUI_SKELETON_POSITION_TRACKING_STATE
&&&NUI_SKELETON_POSITION_NOT_TRACKED = 0,
&&&NUI_SKELETON_POSITION_INFERRED,
&&&NUI_SKELETON_POSITION_TRACKED
} NUI_SKELETON_POSITION_TRACKING_STATE;
各个状态表示的含义:
NUI_SKELETON_POSITION_NOT_TRACKED&& 关节点位置没有跟踪到,而且也不能通过一些信息推断出来,所以关节点的Position&#20540;都为0 。
NUI_SKELETON_POSITION_INFERRED&& 骨骼的关节点位置可以由上一帧数据、已经跟踪到的其他点位置和骨架的几何假设这三个信息推测出来。
NUI_SKELETON_POSITION_TRACKED&& 关节点被成功跟踪,它的位置是基于当前帧的计算得到的。
NUI_SKELETON_POSITION_INDEX:
& & & 另外,SkeletonPositions[20]这个数组是保存20个关节点的位置的,那么哪个数组元素对应哪个关节点呢?实际上,这个数组的保存是有顺序的,然后,我们可以通过下面的枚举&#20540;做为这个数组的下标来访问相应的关节点位置信息:
typedef enum _NUI_SKELETON_POSITION_INDEX
&&&NUI_SKELETON_POSITION_HIP_CENTER = 0,
&&&NUI_SKELETON_POSITION_SPINE,
&&&NUI_SKELETON_POSITION_SHOULDER_CENTER,
&&&NUI_SKELETON_POSITION_HEAD,
&&&NUI_SKELETON_POSITION_SHOULDER_LEFT,
&&&NUI_SKELETON_POSITION_ELBOW_LEFT,
&&&NUI_SKELETON_POSITION_WRIST_LEFT,
&&&NUI_SKELETON_POSITION_HAND_LEFT,
&&&NUI_SKELETON_POSITION_SHOULDER_RIGHT,
&&&NUI_SKELETON_POSITION_ELBOW_RIGHT,
&&& NUI_SKELETON_POSITION_WRIST_RIGHT,
&&&NUI_SKELETON_POSITION_HAND_RIGHT,
&&&NUI_SKELETON_POSITION_HIP_LEFT,
&&&NUI_SKELETON_POSITION_KNEE_LEFT,
&&&NUI_SKELETON_POSITION_ANKLE_LEFT,
&&&NUI_SKELETON_POSITION_FOOT_LEFT,
&&&NUI_SKELETON_POSITION_HIP_RIGHT,
&&&NUI_SKELETON_POSITION_KNEE_RIGHT,
&&&NUI_SKELETON_POSITION_ANKLE_RIGHT,
&&&NUI_SKELETON_POSITION_FOOT_RIGHT,
&&&NUI_SKELETON_POSITION_COUNT
} NUI_SKELETON_POSITION_INDEX;
好了,感觉把这些说完,代码里面的东西就很容易读懂了。所以也没必要赘述了。但是还需要提到的几点是:
NuiTransformSmooth(&skeletonFrame,NULL);
& & & 在骨骼跟踪过程中,有些情况会导致骨骼运动呈现出跳跃式的变化。例如游戏者的动作不够连贯,Kinect硬件的性能等等。骨骼关节点的相对位置可能在帧与帧之间变动很大,这回对应用程序产生一些负面的影响。例如会影响用户体验和给控制造成意外等。
& & & &而这个函数就是解决这个问题的,它对骨骼数据进行平滑,通过将骨骼关节点的坐标标准化来减少帧与帧之间的关节点位置差异。
HRESULT NuiTransformSmooth(
&&&&&&&&NUI_SKELETON_FRAME *pSkeletonFrame,
&&&&&&&&const NUI_TRANSFORM_SMOOTH_PARAMETERS *pSmoothingParams
这个函数可以传入一个NUI_TRANSFORM_SMOOTH_PARAMETERS类型的参数:
typedef struct_NUI_TRANSFORM_SMOOTH_PARAMETERS {
&&&FLOAT fS
&&&FLOAT fC
&&&FLOAT fP
&&&FLOAT fJitterR
&&&FLOAT fMaxDeviationR
} NUI_TRANSFORM_SMOOTH_PARAMETERS;
NUI_TRANSFORM_SMOOTH_PARAMETERS这个结构定义了一些属性:
fSmoothing:平滑&#20540;(Smoothing)属性,设置处理骨骼数据帧时的平滑量,接受一个0-1的浮点&#20540;,&#20540;越大,平滑的越多。0表示不进行平滑
fCorrection:修正&#20540;(Correction)属性,接受一个从0-1的浮点型。&#20540;越小,修正越多。
fJitterRadius:抖动半径(JitterRadius)属性,设置修正的半径,如果关节点“抖动”超过了设置的这个半径,将会被纠正到这个半径之内。该属性为浮点型,单位为米。
fMaxDeviationRadius:最大偏离半径(MaxDeviationRadius)属性,用来和抖动半径一起来设置抖动半径的最大边界。任何超过这一半径的点都不会认为是抖动产生的,而被认定为是一个新的点。该属性为浮点型,单位为米。
fPrediction:预测帧大小(Prediction)属性,返回用来进行平滑需要的骨骼帧的数目。
空间坐标转换:
NuiTransformSkeletonToDepthImage(pSkel-&SkeletonPositions[i], &fx, &fy );
& & & &由于深度图像数据和彩色图像数据来自于不同的摄像头,而这两个摄像头所在的位置不一样,而且视场角等也不也一样,所以产生的图像也会有差别(就好像你两个&#30524;睛看到的东西都不一样,这样大脑才能通过他们合成三维场景理解),也就是说这两幅图像上的像素点并不严&#26684;一一对应。例如深度图像中,你在图像的位置可能是(x1,y1),但在彩色图像中,你在图像的位置是(x2,y2),而两个坐标一般都是不相等的。另外,骨骼数据的坐标又和深度图像和彩色图像的不一样。所以就存在了彩色坐标空间、深度坐标空间、骨骼坐标空间和你的UI坐标空间四个不同的坐标空间了。那么他们各个空间之前就需要交互,例如我在骨骼空间找到这个人在(x1,y1)坐标上,那么对应的深度图像,这个人在什么坐标呢?另外,我们需要把骨骼关节点的位置等画在我们的UI窗口上,那么它们的对应关系又是什么呢?
微软SDK提供了一系列方法来帮助我们进行这几个空间坐标系的转换。例如:
voidNuiTransformSkeletonToDepthImage(
&&&&&&&& Vector4 vPoint,& //骨骼空间中某点坐标
&&&&&&&& FLOAT *pfDepthX, //对应的深度空间中的坐标
&&&&&&&& FLOAT *pfDepthY
)//将骨骼坐标转换到深度图像坐标上去。
HRESULTNuiImageGetColorPixelCoordinatesFromDepthPixel(
&&&&&&&& NUI_IMAGE_RESOLUTION eColorResolution,
&&&&&&&& const NUI_IMAGE_VIEW_AREA *pcViewArea,
&&&&&&&& LONG lDepthX,
&&&&&&&& LONG lDepthY,
&&&&&&&& USHORT usDepthValue,
&&&&&&&& LONG *plColorX,
&& &&&&&&LONG *plColorY
)//获取在深度图中具体坐标位置的像素在相应彩色空间中的像素的坐标。
Vector4NuiTransformDepthImageToSkeleton(
&&&&&&&& LONG lDepthX,
&&&&&&&& LONG lDepthY,
&&&&&&&& USHORT usDepthValue
)//传入深度图像坐标,返回骨骼空间坐标
三、代码及注释
#include &iostream&
#include &opencv/cv.h&
#include &opencv/highgui.h&
//KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK
#include &windows.h&
#include &NuiApi.h&
//KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK
//----各种内核事件和句柄-----------------------------------------------------------------
m_hNextVideoFrameE
m_hNextDepthFrameE
m_hNextSkeletonE
m_pVideoStreamH
m_pDepthStreamH
m_hEvNuiProcessS//用于结束的事件对象;
//---图像大小等参数--------------------------------------------
#define COLOR_WIDTH
#define COLOR_HIGHT
#define DEPTH_WIDTH
#define DEPTH_HIGHT
#define SKELETON_WIDTH
#define SKELETON_HIGHT
#define CHANNEL
#define WIDTH
#define HEIGHT
//---Image stream 分辨率-------------------------------
NUI_IMAGE_RESOLUTION colorResolution = NUI_IMAGE_RESOLUTION_640x480; //设置图像分辨率
NUI_IMAGE_RESOLUTION depthResolution = NUI_IMAGE_RESOLUTION_640x480;
//---显示图像------------------------------------------;
Mat depthRGB(DEPTH_HIGHT,DEPTH_WIDTH,CV_8UC3,Scalar(0,0,0));
//---颜色------------------------------
const Scalar SKELETON_COLORS[NUI_SKELETON_COUNT] =
Scalar(0, 0, 255),
Scalar(0, 255, 0),
Scalar(255, 255, 64),
Scalar(64, 255, 255),
// Light blue
Scalar(255, 64, 255),
Scalar(255, 128, 128)
//深度信息转换为彩色信息,显示人体所在区域;
HRESULT DepthToRGB(USHORT depth, uchar& red, uchar& green, uchar& blue)
SHORT realDepth
= NuiDepthPixelToDepth(depth);
USHORT playerIndex = NuiDepthPixelToPlayerIndex(depth);//获得深度图该点像素位置对应的 UserID;
// Convert depth info into an intensity for display
BYTE b = 255 - static_cast&BYTE&(256 * realDepth / 0x0fff);
switch(playerIndex)
//场景中没有对象时,只绘制灰度图,灰度值[0,128];
green = b/2;
blue = b/2;
green = 0;
blue = b/4;
green = b/4;
green = b/2;
= 255 - b/2;
green = 255 - b/2;
blue = 255 - b/2;
green = 0;
return S_OK;
//获取彩色图像数据,并进行显示
int DrawColor(HANDLE h)
const NUI_IMAGE_FRAME * pImageFrame = NULL;
HRESULT hr = NuiImageStreamGetNextFrame( h, 0, &pImageFrame );
if(FAILED( hr ) )
cout&&&GetColor Image Frame Failed&&&
INuiFrameTexture* pTexture = pImageFrame-&pFrameT
NUI_LOCKED_RECT LockedR
pTexture-&LockRect(0, &LockedRect, NULL, 0 );
if(LockedRect.Pitch != 0 )
BYTE* pBuffer = (BYTE*) LockedRect.pB
//OpenCV显示彩色视频
Mat temp(COLOR_HIGHT,COLOR_WIDTH,CV_8UC4,pBuffer);
imshow(&Color&,temp);
int c = waitKey(1);//按下ESC结束
//如果在视频界面按下ESC,q,Q都会导致整个程序退出
if(c == 27 || c == &#39;q&#39; || c == &#39;Q&#39; )
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&&&GetDepth Image Frame Failed&&&
INuiFrameTexture* pTexture = pImageFrame-&pFrameT
NUI_LOCKED_RECT LockedR
pTexture-&LockRect(0, &LockedRect, NULL, 0 );
if(LockedRect.Pitch != 0 )
BYTE* pBuff = (BYTE*) LockedRect.pB
//OpenCV显示深度视频
Mat depthTmp(DEPTH_HIGHT,DEPTH_WIDTH,CV_16U,pBuff);
//imshow(&Depth&,depthTmp);
depthRGB.setTo(0);
//显示骨骼人体区域信息;
for (int y=0; y&DEPTH_HIGHT; y++)
const USHORT* p_depthTmp = depthTmp.ptr&USHORT&(y);
uchar* p_depthRGB = depthRGB.ptr&uchar&(y);
for (int x=0; x&DEPTH_WIDTH; x++)
USHORT depthValue = p_depthTmp[x];
if (depthValue != 63355)
uchar redValue,greenValue,blueV
DepthToRGB(depthValue,redValue,greenValue,blueValue);
p_depthRGB[3*x] = blueV
p_depthRGB[3*x+1] = greenV
p_depthRGB[3*x+2] = redV
p_depthRGB[3*x]=0;
p_depthRGB[3*x+1]=0;
p_depthRGB[3*x+2]=0;
//imshow(&DepthRGB&,depthRGB);
int c = waitKey(1);//按下ESC结束
if(c == 27 || c == &#39;q&#39; || c == &#39;Q&#39; )
SetEvent(m_hEvNuiProcessStop);
NuiImageStreamReleaseFrame(h, pImageFrame );
//获取骨骼数据,并在深度图上进行显示
int DrawSkeleton()
NUI_SKELETON_FRAME SkeletonF
cv::Point pt[20];
HRESULT hr = NuiSkeletonGetNextFrame( 0, &SkeletonFrame );
if(FAILED( hr ) )
cout&&&GetSkeleton 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=
//Has skeletons!
if(bFoundSkeleton )
NuiTransformSmooth(&SkeletonFrame,NULL);
//cout&&&skeleton num:&&&NUI_SKELETON_COUNT&&
for(int i = 0 ; i & NUI_SKELETON_COUNT ; i++ )
NUI_SKELETON_TRACKING_STATE trackingState = SkeletonFrame.SkeletonData[i].eTrackingS
if(trackingState == NUI_SKELETON_TRACKED )
//骨骼位置跟踪成功,则直接定位;
//NUI_SKELETON_DATA *pSkel = &(SkeletonFrame.SkeletonData[i]);
NUI_SKELETON_DATA
SkelData = SkeletonFrame.SkeletonData[i];
Point jointPositions[NUI_SKELETON_POSITION_COUNT];
for (int j = 0; j & NUI_SKELETON_POSITION_COUNT; ++j)
cout&&j&&& :(&&&SkelData.SkeletonPositions[j].x&&&,&&&SkelData.SkeletonPositions[j].y&&&) &;
NuiTransformSkeletonToDepthImage(SkelData.SkeletonPositions[j], &x, &y, &depth, depthResolution);
//circle(depthRGB, Point(x,y), 5, Scalar(255,255,255), -1, CV_AA);
jointPositions[j] = Point(x, y);
for (int j = 0; j & NUI_SKELETON_POSITION_COUNT; ++j)
if (SkelData.eSkeletonPositionTrackingState[j] == NUI_SKELETON_POSITION_TRACKED)
circle(depthRGB,jointPositions[j],5,SKELETON_COLORS[i],-1,CV_AA);
circle(depthRGB,jointPositions[j],6,Scalar(0,0,0),1,CV_AA);
else if (SkelData.eSkeletonPositionTrackingState[j] == NUI_SKELETON_POSITION_INFERRED)
circle(depthRGB, jointPositions[j], 5, Scalar(255,255,255), -1, CV_AA);
else if(trackingState == NUI_SKELETON_POSITION_INFERRED) //如果骨骼位置跟踪未成功,通过推测定位骨骼位置;
USHORT depth=0;
NuiTransformSkeletonToDepthImage(SkeletonFrame.SkeletonData[i].Position,&x, &y,&depth,depthResolution);
cout&&SkeletonFrame.SkeletonData[i].Position.x&&&;&&&SkeletonFrame.SkeletonData[i].Position.y&&
circle(depthRGB, Point(x, y), 7, CV_RGB(0,0,0), CV_FILLED);
imshow(&SkeletonDepth&,depthRGB);
int c = waitKey(1);//按下ESC结束
if(c == 27 || c == &#39;q&#39; || c == &#39;Q&#39; )
SetEvent(m_hEvNuiProcessStop);
//kinect读取数据流线程;
DWORD WINAPI KinectDataThread(LPVOID pParam)
HANDLE hEvents[4] = {m_hEvNuiProcessStop,m_hNextVideoFrameEvent,
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_hNextVideoFrameEvent, 0))
DrawColor(m_pVideoStreamHandle);
if(WAIT_OBJECT_0 == WaitForSingleObject(m_hNextDepthFrameEvent, 0))
DrawDepth(m_pDepthStreamHandle);
if(WAIT_OBJECT_0 == WaitForSingleObject(m_hNextSkeletonEvent, 0))
DrawSkeleton();
CloseHandle(m_hEvNuiProcessStop);
m_hEvNuiProcessStop= NULL;
CloseHandle(m_hNextSkeletonEvent );
CloseHandle(m_hNextDepthFrameEvent );
CloseHandle(m_hNextVideoFrameEvent );
int main(int argc,char * argv[])
//初始化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 )
cout&&&Nui Initialize Failed&&&
//打开KINECT设备的彩色图信息通道
m_hNextVideoFrameEvent
= CreateEvent( NULL, TRUE, FALSE, NULL );
m_pVideoStreamHandle = NULL;
hr= NuiImageStreamOpen(NUI_IMAGE_TYPE_COLOR,colorResolution, 0,
2,m_hNextVideoFrameEvent, &m_pVideoStreamHandle);
if(FAILED( hr ) )
cout&&&Could not open image stream video&&&
m_hNextDepthFrameEvent
= CreateEvent( NULL, TRUE, FALSE, NULL );
m_pDepthStreamHandle
hr= NuiImageStreamOpen(NUI_IMAGE_TYPE_DEPTH_AND_PLAYER_INDEX,depthResolution, 0,
2, m_hNextDepthFrameEvent,&m_pDepthStreamHandle);
if(FAILED( hr ) )
cout&&&Could not open depth stream video&&&
m_hNextSkeletonEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
//骨骼跟踪事件flag设置:
//坐姿 flag|NUI_SKELETON_TRACKING_FLAG_ENABLE_SEATED_SUPPORT;只有头肩手臂10个节点;
//站姿 flag&~(NUI_SKELETON_TRACKING_FLAG_ENABLE_SEATED_SUPPORT);有20个节点;
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&&&
m_hEvNuiProcessStop
= CreateEvent(NULL,TRUE,FALSE,NULL);//用于结束的事件对象;
//开启一个线程---用于读取彩色、深度、骨骼数据;
HANDLE m_hProcesss
= CreateThread(NULL, 0, KinectDataThread, 0, 0, 0);
///////////////////////////////////////////////
while(m_hEvNuiProcessStop!=NULL)
WaitForSingleObject(m_hProcesss,INFINITE);
CloseHandle(m_hProcesss);
m_hProcesss= NULL;
//Clean up.
NuiShutdown();
显示图像(坐姿,因此只有上肢10个骨骼点):
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:975400次
积分:12207
积分:12207
排名:第685名
原创:177篇
转载:67篇
评论:1146条
小硕一枚,目前从业方向:基于交互式设备的应用研发,主要关注:Kinect、LeapMotion、Oculus等交互式设备或可穿戴设备 ;希望和大家交流,共同提高。大家如果对文章有什么问题,发邮件可能无法及时回复,请直接在文章评论栏留言。本人微博:
文章:15篇
阅读:59946
文章:71篇
阅读:501244
(1)(1)(2)(3)(1)(1)(3)(1)(5)(3)(1)(1)(1)(7)(1)(18)(7)(6)(14)(9)(15)(48)(12)(19)(6)(4)(7)(17)(26)(9)}

我要回帖

更多关于 设备管理器怎么打开 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信