Kinect for Windows SDK v2.0 开发笔记 (二)彩色帧获取

转载于:https://blog.csdn.net/dustpg/article/details/40398987

使用SDK: Kinect for Windows SDK v2.0 1409

在9月更新中, x86的Fusion终于可以使用了,这次说Fusion吧.

Fusion不再是所谓的“Fusion帧”了, 而是向一代靠齐,以NUI开头,可见算法与一代一样。

还是仅仅是降低代码移植成本?


所以找了找一代的说明:

Kinect Fusion能够基于深度图像,实时对场景进行重建。

设备能够使用GPU或者CPU进行计算:

[cpp]  view plain  copy
  1. enum _NUI_FUSION_RECONSTRUCTION_PROCESSOR_TYPE  
  2.     {  
  3.         NUI_FUSION_RECONSTRUCTION_PROCESSOR_TYPE_CPU    = 1,  
  4.         NUI_FUSION_RECONSTRUCTION_PROCESSOR_TYPE_AMP    = 2  
  5.     }   NUI_FUSION_RECONSTRUCTION_PROCESSOR_TYPE;  

可见GPU加速使用的是C++AMP技术。

1代说明地址:http://msdn.microsoft.com/us-en/library/dn188670.aspx

Fusion将收集的数据慢慢"融合"起来


这是因为期间发动了“再融合”,从而使物品表面光滑(误)


Fusion工作管线:



需要的额外文件:

即Fusion的dll文件,使用命令:

xcopy /C /Y "$(KINECTSDK20_DIR)Redist\Fusion\x86\Kinect20.Fusion.dll" "$(OutDir)"

复制过来即可,头文件与库文件:
#include <NuiKinectFusionApi.h>
#pragma comment ( lib, "Kinect20.Fusion.lib" )

请注意以后SDK更新后,文件名的改变


基本Fusion步骤:

0. 设备检查:

    Fusion对图形设备是有要求的,需要DX11的支持,可以进行设备检测:

[cpp]  view plain  copy
  1. // 获取设备信息:: 可以用于debug  
  2. WCHAR description[MAX_PATH];  
  3. WCHAR instancePath[MAX_PATH];  
  4. UINT memorySize = 0;  
  5. if (SUCCEEDED(hr)){  
  6.     hr = NuiFusionGetDeviceInfo(  
  7.         m_processorType,  
  8.         m_deviceIndex,  
  9.         description,  
  10.         lengthof(description),  
  11.         instancePath,  
  12.         lengthof(instancePath),  
  13.         &memorySize  
  14.         );  
  15.     if (hr == E_NUI_BADINDEX){  
  16.         ::MessageBoxW(nullptr, L"需要DX11支持", L"错误", MB_ICONERROR);  
  17.     }  
  18. }  

NuiFusionGetDeviceInfo第一个参数是设备类型,就是 CPU还是GPU,

第二个是设备索引,标记-1使用默认设备。这次就-1,使用默认设备,下次枚举设备。

其他参数就不说了。

1. 创建Fusion 容积重建INuiFusionReconstruction

  核心函数NuiFusionCreateReconstruction:

参数1: 容积重建参数

参数2: 设备类型

参数3: 设备索引

参数4: 世界到相机 坐标转换矩阵

参数5: 返回指针

参数1中:

[cpp]  view plain  copy
  1. typedef struct _NUI_FUSION_RECONSTRUCTION_PARAMETERS  
  2.     {  
  3.     FLOAT voxelsPerMeter;  
  4.     UINT voxelCountX;  
  5.     UINT voxelCountY;  
  6.     UINT voxelCountZ;  
  7.     }   NUI_FUSION_RECONSTRUCTION_PARAMETERS;  


从上到下依次是

    每米体素(体积元素或者体积像素)数量

    重建X轴体素数量

    重建Y轴体素数量

    重建Z轴体素数量

SDK中使用的数据为:

[cpp]  view plain  copy
  1. m_reconstructionParams.voxelsPerMeter = 256.f;  
  2. m_reconstructionParams.voxelCountX = 384;  
  3. m_reconstructionParams.voxelCountY = 384;   
  4. m_reconstructionParams.voxelCountZ = 384;   

即每米有256个体素,每两个临近的体素距离约为4mm.

建立了1.5m*1.5m*1.5m的容积,消耗内存384*384*384*4,200+MB(可能还有内存对齐消耗的内存)

GPU加速即显卡内存,CPU加速即系统内存,这可是一笔大买卖啊。

目前主流显存在1G~2G,差强人意。


创建后,可能会进行检错:

[cpp]  view plain  copy
  1. if (hr == E_NUI_GPU_FAIL){  
  2.     ::MessageBoxW(nullptr, L"显卡不支持Fusion计算!\n或者 初始化失败", L"错误", MB_ICONERROR);  
  3. }  
  4. else if (hr == E_NUI_GPU_OUTOFMEMORY){  
  5.     ::MessageBoxW(nullptr, L"显存不足", L"错误", MB_ICONERROR);  
  6. }  


1.5. 查看世界到容积坐标转换矩阵:

之前成功后,我们可以看看创建后的世界到容积坐标转换矩阵

[cpp]  view plain  copy
  1. if (SUCCEEDED(hr)){  
  2.         hr = m_pReconstruction->GetCurrentWorldToVolumeTransform(&m_defaultWorldToVolumeTransform);  
  3.     }  

设置断点后我们可以查看其值如下:

256   0     0     0

0     256   0     0

0       0    256  0

192 192   0     1

(0.75, 0.75, 1.5)经过转换后即为(384, 384, 384),即容积的边界点.

通过修改世界到容积转换矩阵可以控制重建范围.

2. 创建需要的Fusion图像帧:

  Fusion图像帧储存了需要的数据,类型有:

[cpp]  view plain  copy
  1. typedef   
  2. enum _NUI_FUSION_IMAGE_TYPE  
  3.     {  
  4.         NUI_FUSION_IMAGE_TYPE_INVALID   = 0,  
  5.         NUI_FUSION_IMAGE_TYPE_COLOR = 1,  
  6.         NUI_FUSION_IMAGE_TYPE_FLOAT = 2,  
  7.         NUI_FUSION_IMAGE_TYPE_POINT_CLOUD   = 3  
  8.     }   NUI_FUSION_IMAGE_TYPE;  

即色彩、浮点与点云。

我们需要将收集的深度数据浮点化,再平滑化(可选),计算出点云后,输出表面(可选)与法线图像(可选)。

即需要5张Fusion图像帧

[cpp]  view plain  copy
  1. // 创建浮点深度帧  
  2. if (SUCCEEDED(hr)){  
  3.     hr = NuiFusionCreateImageFrame(  
  4.         NUI_FUSION_IMAGE_TYPE_FLOAT,   
  5.         m_cDepthWidth,   
  6.         m_cDepthHeight,   
  7.         nullptr,  
  8.         &m_pDepthFloatImage  
  9.         );  
  10. }  
  11. // 创建平滑浮点深度帧  
  12. if (SUCCEEDED(hr)){  
  13.     hr = NuiFusionCreateImageFrame(  
  14.         NUI_FUSION_IMAGE_TYPE_FLOAT,   
  15.         m_cDepthWidth,   
  16.         m_cDepthHeight,  
  17.         nullptr,  
  18.         &m_pSmoothDepthFloatImage  
  19.         );  
  20. }  
  21. // 创建点云帧  
  22. if (SUCCEEDED(hr)){  
  23.     hr = NuiFusionCreateImageFrame(  
  24.         NUI_FUSION_IMAGE_TYPE_POINT_CLOUD,  
  25.         m_cDepthWidth,  
  26.         m_cDepthHeight,  
  27.         nullptr,  
  28.         &m_pPointCloud  
  29.         );  
  30. }  
  31. // 创建Fusion图像帧  
  32. if (SUCCEEDED(hr)){  
  33.     hr = NuiFusionCreateImageFrame(  
  34.         NUI_FUSION_IMAGE_TYPE_COLOR,  
  35.         m_cDepthWidth,  
  36.         m_cDepthHeight,  
  37.         nullptr,  
  38.         &m_pSurfaceImageFrame  
  39.         );  
  40. }  
  41. // 创建Fusion法线帧  
  42. if (SUCCEEDED(hr)){  
  43.     hr = NuiFusionCreateImageFrame(  
  44.         NUI_FUSION_IMAGE_TYPE_COLOR,  
  45.         m_cDepthWidth,  
  46.         m_cDepthHeight,  
  47.         nullptr,  
  48.         &m_pNormalImageFrame  
  49.         );  
  50. }  

这样初始化基本完成了,不过需要重置一下:

INuiFusionReconstruction::ResetReconstruction
参数一: 新的目标 世界到相机 坐标转换矩阵

参数二: 新的目标 世界到容积 坐标转换矩阵

好了,初始化完成:


3. Fusion处理

Fusion是基于深度帧的,所以应该在深度图像中处理,

获取到深度数据后(前略):

转换为浮点型深度

INuiFusionReconstruction::DepthToDepthFloatFrame


之前说了,可以平滑化数据:

INuiFusionReconstruction::SmoothDepthFloatFrame


接下来处理该帧

INuiFusionReconstruction::ProcessFrame

这是一个较为高级的方法, 原文说了:

This is usually the camera pose result from the most recent call to the AlignPointClouds or AlignDepthFloatToReconstruction method.

可以调用这两个较低级的方法.


可能会处理错误:

[cpp]  view plain  copy
  1. // 检查错误  
  2. if (hr4f == E_NUI_FUSION_TRACKING_ERROR){  
  3.     m_ImagaRenderer.error_info = L"Fusion跟踪失败, 请保证目标是静态的,\n请常试重建(单击窗口)";  
  4. }  
  5. else if(SUCCEEDED(hr)){  
  6.     m_ImagaRenderer.error_info = L"Fusion跟踪正常";  
  7. }  
  8. else{  
  9.     m_ImagaRenderer.error_info = L"Fusion跟踪失败";  
  10. }  


计算出点云帧:

INuiFusionReconstruction::CalculatePointCloud


为点云帧着色(Shade)

NuiFusionShadePointCloud

输出表面与法线, 这将是我们显示的图像.

值得注意的是参数三:世界到BGR转换矩阵,

即将坐标XYZ转换为颜色BGR,Kinect中,XY可正可负,Z则一直为正,所以,我们这里

的转换矩阵是可以这样:

[cpp]  view plain  copy
  1. Matrix4 worldToBGRTransform = { 0.0f };  
  2. worldToBGRTransform.M11 = m_reconstructionParams.voxelsPerMeter / m_reconstructionParams.voxelCountX;  
  3. worldToBGRTransform.M22 = m_reconstructionParams.voxelsPerMeter / m_reconstructionParams.voxelCountY;  
  4. worldToBGRTransform.M33 = m_reconstructionParams.voxelsPerMeter / m_reconstructionParams.voxelCountZ;  
  5. worldToBGRTransform.M41 = 0.5f;  
  6. worldToBGRTransform.M42 = 0.5f;  
  7. worldToBGRTransform.M43 = 0.0f;  
  8. worldToBGRTransform.M44 = 1.0f;  


我们还顺带计算了各个方法的耗时, 响应WM_LBUTTONUP消息以重建容积等等.

这就是成果图了:


可以看出各个都是吃时间的大东西。。。


这节就是说是基本的Fusion,代码下载地址:点击这里



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值