getUserPixels - 官方Kinect SDK的替代品

时间:2012-12-12 19:22:01

标签: kinect openni

官方Kinect SDK中OpenNI提供的getUserPixels方法是否有替代方法?

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

1 个答案:

答案 0 :(得分:1)

官方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;
                }
            }
        }
    }
}

然后,当下一个深度框准备就绪时,我会为与BitmapMask对应的用户提取playerIndex

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函数。鉴于深度框架和playerIndex:

,您感兴趣的重要部分将是
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
        }
    }
}