(转载请注明出处)
使用SDK: Kinect for Windows SDK v2.0 public preview
好了,真正正式进入SDK的学习当中。
同大多数Kinect相关的文章,第一个自然也是获取它那1080P的彩色图像。
值得说明的是,这次Kinect支持不同的程序使用同一个Kinect,至于有没有坏处,
毕竟不是这方面的专家,不敢出狂言,只是隐约感觉到了一点蛋疼。
好了,可以使用上节给的模板创建项目了,需要简单配置一下项目,选择项目属性后请按照图中一样设置
里面的"KINECTSDK20_DIR"是一个环境变量,可以在系统属性-高级-环境变量 里边查看/修改
再在stdafx.h里面添加
#include
#pragma comment ( lib, "kinect20.lib" )
好了,COM组件是基于面向对象模型的接口,那么Kinect的类是什么呢,是KinectSensor,
比一代的NUISensor好点了。不过COM只提供了接口,于是叫做IKinectSensor。
使用
GetDefaultKinectSensor(IKinectSensor**)获取一个默认的Kinect。如果有复数台Kinect可以使用
GetKinectSensorCollection(IKinectSensorCollection** )进行枚举,代码大致如下
IKinectSensorCollection* pKinectCollection = nullptr;
IEnumKinectSensor* pEnumKinect = nullptr;
IKinectSensor* pKinect = nullptr;
// 获取Kinect集合
HRESULT hr = ::GetKinectSensorCollection(&pKinectCollection);
// 获取Kinect枚举器
if (SUCCEEDED(hr)){
hr = pKinectCollection->get_Enumerator(&pEnumKinect);
}
// 枚举Kinect
if (SUCCEEDED(hr)){
BOOLEAN available = false;
while (true){
// 获取下一个
if (SUCCEEDED(pEnumKinect->GetNext(&pKinect))){
// 判断有效性
pKinect->get_IsAvailable(&available);
if (available && YourJudgmentFunc(pKinect)){
break;
}
SafeRelease(pKinect);
}
else
break;
}
}
SafeRelease(pEnumKinect);
SafeRelease(pKinectCollection);
不过!等等!居然看到小写的方法名:get_IsAvailable,夭寿啦,微软居然有小写开头的方法,长这么大第一次看到啊(笔者见识短,见谅)
是的,Kinect SDK中存在大量的get_开头的方法,不过本人觉得Kinect的类太多了,虽然很好,但是效率与易用性会下降啊,
直接Kinect::GetColorFrameData也不错,简单粗暴。
IKinectSensor::Open() 绅士地打开传感器
IKinectSensor::Close() 优雅地关闭传感器
那么怎么获取彩色帧呢,没有一代那样打开指定功能。
一代获取彩色帧需要先说明“我要获取彩色帧啦”,然后指定彩色帧格式。
二代设计上简单了,直接获取彩色帧相关对象几个,目前还不能设置获取分辨率。
本人估计为了达到“多个程序使用一个Kinect”的效果,二代干脆直接一股脑像扔垃圾一样全扔过来了,
你要啥自己到地上捡,不需要像一代那样开发票啦!
使用
IKinectSensor::get_ColorFrameSource(IColorFrameSource**)
获取一个ColorFrameSource(彩色帧源)
再使用
IColorFrameSource::OpenReader(IColorFrameReader **)
打开一个ColorFrameReader(彩色帧读取器)
再使用
IColorFrameReader::AcquireLatestFrame(IColorFrame**)
获取彩色帧,有就返回S_OK,否则返回错误代码
这个称为轮询模式,有空的时候来问一下Kinect有没有新的彩色帧,这个模式适合游戏 ,
在每帧询问一下,毕竟游戏是每帧都要刷新的
还有一个称为事件模式,这个就适合其他一般程序啦。
Windows下使用WaitForSingleObject、WaitForMultipleObjects等待事件用于线程同步,
详细可以参考其他文章,关键函数有CreatEvent, SetEvent, ResetEvent等。
这里是用的是MsgWaitForMultipleObjects,这个函数不仅可以等待内核对象,还能对Windows消息进行响应,
当然,详细的可以自行搜索一下。
MsgWaitForMultipleObjects(lengthof(events), events, FALSE, INFINITE, QS_ALLINPUT);
比如这里用这个
event是个静态数组,lengthof是个宏,定义如下,判断静态数组的长度
#define lengthof(a) (sizeof(a)/sizeof(*a))
怎么获取呢?
在打开ColorFrameReader后不要急,IColorFrameReader::SubscribeFrameArrived(WAITABLE_HANDLE*)
获取事件即可,使用时上边的
events[0] = reinterpret_cast(hColorFrameArrived)
强制转换即可
当彩色临帧事件被触发时,
IColorFrameReader::GetFrameArrivedEventData(WAITABLE_HANDLE, IColorFrameArrivedEventArgs**)
来获取事件的数据
再使用
IColorFrameArrivedEventArgs::get_FrameReference(IColorFrameReference**)
获取彩色帧引用
最后使用
IColorFrameReference::AcquireFrame(IColorFrame**)
获取彩色帧
说到这里,只想说: 我去,微软你累不累。
好了,这样,事件与轮询两个模式终于同步了。
目前,彩色帧分辨率固定为1920*1080,不过为了保证以后能自行设置采样分辨率,
所以应该获取获取的彩色帧分辨率
使用IColorFrame::get_FrameDescription获取彩色帧描述,再利用这个描述获取宽度与高度
自然还需要获取源数据格式,我们需要的是BGRA格式,
使用IColorFrame::get_RawColorImageFormat检查格式,如果是ColorImageFormat_Bgra后
可以直接使用
IColorFrame::AccessRawUnderlyingBuffer(UINT*, BYTE**)
获取该帧数据地址与长度,BGRA顺序的位图。
如果不是BGRX格式的,可以用自带的转换方法进行转换,不过这个方法需要自备缓冲区,
自己在构造函数里面new[]一个就好了,记得在析构函数里面释放
自带的方法是:
IColorFrame::CopyConvertedFrameDataToArray(UINT, BYTE*,ColorImageFormat)
然后就完事大吉,用自己想用的图像接口显示吧:
嗯,光线不是特别好,寝室很乱,见笑了
附加:
提供FPS显示与鼠标缩放功能与显示,详细的请看范例,再根据例子讲本工程补全吧。
还有就是不知道为什么有时15FPS,有时30FPS,简直了...
本节范例下载