getUserPixels-官方Kinect SDK中的替代方案



官方Kinect SDK中有OpenNI提供的getUserPixels方法的替代方案吗?

如何使用官方Kinect SDK实现此功能?

官方的Kinect for Windows SDK(v1.6)不支持直接调用(如getUserPixels)来提取播放器轮廓,但包含了提取所需的所有信息。

通过查看Kinect for Windows Developer Toolkit中的两个示例,您可以以不同的方式看到这一点。

  • 基本交互WPF:包括一个创建被跟踪用户的简单轮廓的功能
  • 绿屏(-WPF或-D2D):显示如何执行背景减法以产生绿屏效果。在该示例中,来自RGB相机的数据被叠加在图像上

这两个示例以不同的方式实现这一点。

  • 基本交互将从深度数据中提取对应于请求玩家的BitmapMask。这样做的优点是只显示被跟踪的用户;任何不被认为是骨架的对象都会被忽略
  • 绿屏不寻找特定的用户,而是选择运动。这就提供了屏蔽任何移动物体的优势,比如在两个用户之间传球

我相信"基本交互"示例将向您展示如何实现您想要的内容。你必须自己做这项工作,但这是可能的。例如,以"基本交互"为基础,我创建了一个UserControl,它生成了被跟踪用户的简单轮廓。。。

当骨架框架准备好时,我拉出玩家索引:

private void OnSkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
{
using (SkeletonFrame skeletonFrame = e.OpenSkeletonFrame())
{
if (skeletonFrame != null && skeletonFrame.SkeletonArrayLength > 0)
{
if (_skeletons == null || _skeletons.Length != skeletonFrame.SkeletonArrayLength)
{
_skeletons = new Skeleton[skeletonFrame.SkeletonArrayLength];
}
skeletonFrame.CopySkeletonDataTo(_skeletons);
// grab the tracked skeleton and set the playerIndex for use pulling
// the depth data out for the silhouette.
// NOTE: this assumes only a single tracked skeleton!
this.playerIndex = -1;
for (int i = 0; i < _skeletons.Length; i++)
{
if (_skeletons[i].TrackingState != SkeletonTrackingState.NotTracked)
{
this.playerIndex = i+1;
}
}
}
}
}

然后,当下一个深度帧准备好时,我为对应于playerIndex的用户拉出BitmapMask

private void OnDepthFrameReady(object sender, DepthImageFrameReadyEventArgs e)
{
using (DepthImageFrame depthFrame = e.OpenDepthImageFrame())
{
if (depthFrame != null)
{
// check if the format has changed.
bool haveNewFormat = this.lastImageFormat != depthFrame.Format;
if (haveNewFormat)
{
this.pixelData = new short[depthFrame.PixelDataLength];
this.depthFrame32 = new byte[depthFrame.Width * depthFrame.Height * Bgra32BytesPerPixel];
this.convertedDepthBits = new byte[this.depthFrame32.Length];
}
depthFrame.CopyPixelDataTo(this.pixelData);
for (int i16 = 0, i32 = 0; i16 < pixelData.Length && i32 < depthFrame32.Length; i16++, i32 += 4)
{
int player = pixelData[i16] & DepthImageFrame.PlayerIndexBitmask;
if (player == this.playerIndex)
{
convertedDepthBits[i32 + RedIndex] = 0x44;
convertedDepthBits[i32 + GreenIndex] = 0x23;
convertedDepthBits[i32 + BlueIndex] = 0x59;
convertedDepthBits[i32 + 3] = 0x66;
}
else if (player > 0)
{
convertedDepthBits[i32 + RedIndex] = 0xBC;
convertedDepthBits[i32 + GreenIndex] = 0xBE;
convertedDepthBits[i32 + BlueIndex] = 0xC0;
convertedDepthBits[i32 + 3] = 0x66;
}
else
{
convertedDepthBits[i32 + RedIndex] = 0x0;
convertedDepthBits[i32 + GreenIndex] = 0x0;
convertedDepthBits[i32 + BlueIndex] = 0x0;
convertedDepthBits[i32 + 3] = 0x0;
}
}
if (silhouette == null || haveNewFormat)
{
silhouette = new WriteableBitmap(
depthFrame.Width,
depthFrame.Height,
96,
96,
PixelFormats.Bgra32,
null);
SilhouetteImage.Source = silhouette;
}
silhouette.WritePixels(
new Int32Rect(0, 0, depthFrame.Width, depthFrame.Height),
convertedDepthBits,
depthFrame.Width * Bgra32BytesPerPixel,
0);
Silhouette = silhouette;
this.lastImageFormat = depthFrame.Format;
}
}
}

我最终得到的是WriteableBitmap中用户的紫色剪影,它可以复制到控件上的Image,也可以被拉到其他地方使用。一旦你有了BitmapMask,如果你想真正看到与该区域对应的RGB数据,你也可以将数据映射到颜色流。

如果您愿意,可以调整代码以更接近地模拟getUserPixels函数。你感兴趣的主要部分是,给定深度框架和播放器索引:

if (depthFrame != null)
{
// check if the format has changed.
bool haveNewFormat = this.lastImageFormat != depthFrame.Format;
if (haveNewFormat)
{
this.pixelData = new short[depthFrame.PixelDataLength];
this.depthFrame32 = new byte[depthFrame.Width * depthFrame.Height * Bgra32BytesPerPixel];
this.convertedDepthBits = new byte[this.depthFrame32.Length];
}
depthFrame.CopyPixelDataTo(this.pixelData);
for (int i16 = 0, i32 = 0; i16 < pixelData.Length && i32 < depthFrame32.Length; i16++, i32 += 4)
{
int player = pixelData[i16] & DepthImageFrame.PlayerIndexBitmask;
if (player == this.playerIndex)
{
// this pixel "belongs" to the user identified in "playerIndex"
}
else
{
// not the requested user
}
}
}

最新更新