0

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

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

4

1 回答 1

1

官方 Kinect for Windows SDK (v1.6) 不支持直接调用,例如getUserPixels提取玩家剪影,但确实包含执行此操作所需的所有信息。

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

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

这两个示例以不同的方式执行此操作。

  • Basic InteractionsBitmapMask将从与请求的玩家对应的深度数据中提取一个。这样做的好处是只显示被跟踪的用户;任何不被认为是骨架的物体都会被忽略。
  • 绿屏不寻找特定用户,而是选择运动。这提供了对任何移动物体进行剪影的优势——例如在两个用户之间传递的球。

我相信“基本交互”示例将向您展示如何实现您正在寻找的内容。您必须自己完成这项工作,但这是可能的。例如,使用“基本交互”示例作为基础,我创建了一个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;
        }
    }
}

我最终得到的是 a 中用户的紫色剪影WriteableBitmap,可以将其复制到Image控件上的 an 或拉出并在其他地方使用。一旦你有了,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
        }
    }
}
于 2012-12-12T21:44:01.323 回答