Kinectfor WindowsSDK是一个强大的工具,它允许开发者访问Kinect传感器的高级功能。本文是一系列教程的一部分,旨在为初学者提供指导,并为高级开发者提供参考。在第一部分中,介绍了Kinect SDK的初始化过程,包括图像捕获引擎的参数设置。本文将专注于通过Kinect摄像头获取和处理数据。
Kinect设备配备了两个摄像头:
本文将重点介绍如何获取和处理这些摄像头捕获的数据。
ImageStream是KinectSDK提供的一个类,用于访问Kinect摄像头捕获的数据。每个Kinect运行时有两个流:
如第一部分所述,每个流在运行时初始化后都必须调用Open()方法。流所需的第三个参数是ImageResolution,可选值有80x60、320x240、640x480和1280x1024。请注意,DepthStream的最大分辨率为640x480,不同的ImageType支持不同的分辨率。
使用ImageStream非常简单。可以调用GetNextFrame方法,或者订阅运行时暴露的事件:DepthFrameReady或VideoFrameReady。如果使用事件,将通过ImageFrameReadyEventArgs.ImageFrame获取帧数据。
使用上述任何方法,将获得一个ImageFrame,它在Image字段中持有图像数据本身,以及一些元数据,如:
FrameNumber和Timestamp相当准确,如果需要检测丢失的帧、测量帧之间的时间、保持视频和深度之间的同步,或者如果不需要每秒获取新图像超过一次,它们将非常有价值。
KinectSDK提供了自己的类来保存捕获的图像。它非常简单,只包含Width、Height、BytesPerPixel和原始数据byte[] Bits。
视频帧以32位XRGB或16位UYVY格式保存信息。深度帧根据选择的Depth或DepthAndPlayerIndex流类型有两种不同的格式:
值为0的深度数据意味着该位置的物体要么太近要么太远。
源代码中包含的PlanarImageHelper类简化了对单个像素的访问:
public class PlanarImageHelper
{
private PlanarImage _img;
public PlanarImage Image
{
get { return _img; }
}
public PlanarImageHelper(PlanarImage src)
{
_img = src;
}
public Byte GetRedAt(int x, int y)
{
return _img.Bits[y * _img.Width * _img.BytesPerPixel + x * _img.BytesPerPixel + 2];
}
public Byte GetGreenAt(int x, int y)
{
return _img.Bits[y * _img.Width * _img.BytesPerPixel + x * _img.BytesPerPixel + 1];
}
public Byte GetBlueAt(int x, int y)
{
return _img.Bits[y * _img.Width * _img.BytesPerPixel + x * _img.BytesPerPixel + 0];
}
public int GetPlayerAt(int x, int y)
{
return _img.Bits[y * _img.Width * _img.BytesPerPixel + x * _img.BytesPerPixel] & 0x07;
}
public int GetDepthAt(int x, int y, bool hasPlayerData)
{
try
{
int BaseByte = y * _img.Width * _img.BytesPerPixel + x * _img.BytesPerPixel;
if (hasPlayerData)
{
return (_img.Bits[BaseByte + 1] << 5) | (_img.Bits[BaseByte] >> 3);
}
else
{
return (_img.Bits[BaseByte + 1] << 8) | (_img.Bits[BaseByte]);
}
}
catch
{
return 0;
}
}
}
在附带的源代码中,将找到ImageStreamTest应用程序。这是一个简单的示例,展示了ImageStreams的使用和深度数据的利用。
在窗口的左侧,可以根据深度数据选择应用于图像的效果:
这取决于需求。正如在例子中看到的,选择了“迭代”方法,因为它非常简单易写,也非常清晰易读。
另一方面,它的性能非常差。由于深度帧可以被视为灰度图像,可以使用所有好的图像处理库中容易找到的过滤器(如阈值和掩码)来实现与例子相同的效果。
首先,必须决定真正需要什么。如果正在构建一个增强现实应用程序,那么需要高质量的视频和快速的图像混合。如果只是偶尔分析图像的一部分(例如面部识别),那么需要高分辨率的图像,但不需要高fps,这意味着可以在事件处理程序中跳过每帧的处理,并按需获取帧。
正如前面部分所看到的,Kinect SDK以非常原始的格式提供图像。这意味着它可以很容易地转换为所需要的任何东西。大多数图形库都能够以最有效的方式接受这个原始字节数组,并创建内部图像表示。