0

公式の Kinect SDK でOpenNIgetUserPixelsが提供する方法に代わるものはありますか?

この機能を公式の Kinect SDK でどのように実装しますか?

4

1 に答える 1

1

公式の Kinect for Windows SDK (v1.6) は、プレーヤーのシルエットを抽出するための などの直接呼び出しをサポートしていませんが、getUserPixelsそのために必要なすべての情報が含まれています。

Kinect for Windows Developer Toolkitから入手できる 2 つの例を調べることで、さまざまな方法でこれを実際に確認できます。

  • Basic Interactions-WPF : 追跡されているユーザーの単純なシルエットを作成する機能が含まれています。
  • グリーン スクリーン (-WPF、または -D2D) : バックグラウンド減算を実行してグリーン スクリーン効果を生成する方法を示します。この例では、RGB カメラからのデータが画像に重ねられています。

2 つの例では、これを異なる方法で行っています。

  • Basic InteractionsBitmapMaskは、要求されたプレーヤーに対応する深さデータからを引き出します。これには、追跡されたユーザーのみを表示するという利点があります。スケルトンと見なされないオブジェクトは無視されます。
  • Green Screenは特定のユーザーを探すのではなく、モーションを選択します。これにより、2 人のユーザーの間でボールが渡されるなど、動くオブジェクトをシルエット化する利点が得られます。

「基本的な相互作用」の例は、探しているものをどのように実装するかを示していると思います。作業は自分で行う必要がありますが、可能です。たとえば、「基本的なインタラクション」の例をベースとして使用し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
        }
    }
}
于 2012-12-12T21:44:01.323 に答える