Kinect坐标系概述

基于前面的几篇Kinect文章,我们知Kinect有3个摄像头,其中可获得彩色、深度数据的接收机, 类似人的两个眼睛。 目前,Kinect总共有3个坐标系,分别是骨骼坐标系、深度坐标系、彩色图像坐标系。那么就涉及到了如何把这些个坐标系柔和在一起:如可以使得骨骼数据和颜色数据一起呈现(80%的应用会用到),深度数据和骨骼数据一起呈现等等。

庆幸的是微软提供了一个CoordinateMapper来帮助我们做这些事情:

MapDepthPointToColorPoint

MapDepthPointToSkeletonPoint

MapSkeletonPointToColorPoint

MapSkeletonPointToDepthPoint

ColorImagePoint:彩色图像坐标,含x、y、z

DepthImagePoint:深度坐标,含x、y、z(Depth)

SkeletonPoint:骨骼坐标,含x、y、z

image

图片来自余涛的《Kinect开发应用》书截图。

Kinect采集的数据源之一:Skeleton

严格意义上来说,Skeleton数据(骨骼数据)不算是Kinect采集上来的数据,应该是通过算法、驱动算出来(匹配)出来的一个结果。具体可参看微软官网上这篇著名的论文,《Real-Time Human Pose Recognition in Parts from a Single Depth Image

 

Kinect V1版本20个Joint图

在V1版本的Kinect中,如上图,提供了20个骨骼,最多可同时跟踪2个人的骨骼数据,是否开启骨骼数据,通过观察任务管理器可看到比较耗费CPU和内存。

看了一段时间的Kinect新闻后,猜测约有80%的程序(应用)是基于骨骼数据做的,故骨骼数据非常有嚼头–姿势、动作识别,控制虚拟人等。

Kinect采集的数据源之一:Depth

Kinect最有用的数据,Depth–深度数据、景深数据,其核心芯片来源参见文章《可以WPF编程的玩具:Xbox 360 Kinect–芯片》。 Depth数据提供了80mm~4m范围的深度数据(Near模式下,范围为40mm~4m),同时也提供了PlayerIndex(但在实验中,发现PlayerIndex不稳定,且渲染出人性轮廓和周边物体区分开不太清晰).

使用Depth数据,类似Color数据,也仅需三步:

步骤一:初始化Kinect

步骤二:配置Depth参数DepthImageFormat

步骤三:响应回调函数,处理DepthImageFrame数据

返回的Depth数据,实质上是一堆short[],其中每个short类型代表一个深度数据:

int player = srcData[i] & DepthImageFrame.PlayerIndexBitmask;
int realDepth = srcData[i] >> DepthImageFrame.PlayerIndexBitmaskWidth;

 

PlayerIndexBitmask是常量7,PlayerIndexBitmaskWidth是常量3.即后三位为PlayerID,前面13为为毫米的深度数据。

雷区:

1 PlayIndex会变化:当你走出FOV区域后,再次走进来,这个会变化。

2 要启用Depth数据,需要开通SkeletonStream.Enable。

 

Kinect的应用中,用到Depth数据的很多,约有20%吧! 其中测量身高是比较有趣的一个。 且,骨骼数据来自Depth数据。 有一些受限的条件是需要大于2.3米才可完整的展现一个人在屏幕中,故屏幕要大些才可看到清晰的图像。

Kinect采集的数据源之一:Color

即普通的彩色摄像头,能获得RGB数据流,后期可显示实时图像,如用第三方类库(Coding4Fun Kinect Toolkit),可保存图片、视频文件。

使用Color数据,非常方便,通过下面的三步操作即可:

步骤一 启动Kinect:

通过查询KinectStatus.Connected的Kinect返回即可。

KinectSensor这个对象,不能new,需要从KinectSensor.KinectSensors数组中便利获得。

步骤二 配置Color的参数:

Kinect提供了ColorImageFormat类型的7种Color图像格式。常用的RgbResolution640x480Fps30,640和480的图像,每秒30帧图像。还有Yuv、Bayer、Infrared三种高级图像格式。

步骤三 Color回调函数:

可获得ColorImageFrame类对象数据,而实际的Color数据存储在byte[]中。

 

雷区

WriteableBitmap.Create(data.Width, data.Height, 96, 96,PixelFormats.Bgr32, null, data, data.Width * 4);

 

因为选择的是Bgr32图像呈现,而API接口如下中的stride老是传递不对

BitmapSource Create(int pixelWidth, int pixelHeight, double dpiX, double dpiY, PixelFormat pixelFormat, BitmapPalette palette, Array pixels, int stride);

后来才摸索出来规律:

  • RgbResolution1280x960Fps12    Bgr32  4字节
  • RgbResolution640x480Fps30      Bgr32  4字节
  • InfraredResolution640x480Fps30    Gray16 2字节

相对于目前手机的高配彩色摄像头,XBox 360 Kinect的这个彩色摄像头,分辨率比较差:仅仅能呈现640*480像素的, 连720P都达不到。还有一种设置是1280*960分辨率,稍微清晰,可惜是15FPS(低于24FPS的,实时录像会有拖影,影响效果)

比较期待今年7月15号发布的Kinect V2版本,据说可以获得1080P的彩色图像。