Kinectの背景除去

I followed the code provided by Robert Levy at this link: http://channel9.msdn.com/coding4fun/kinect/Display-Kinect-color-image-containing-only-players-aka-background-removal

私はそれを私の既存のコードに実装しようとしましたが、矛盾した結果がありました。プログラムの起動時にユーザがkinectの視界にいる場合、時間の一部をバックグラウンドで削除します。ユーザが視界に入ると、それを拾いません。

    namespace KinectUserRecognition
    {
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }

            //Kinect Runtime
            Runtime kinect = Runtime.Kinects[0];

            PlanarImage colorImage;
            PlanarImage depthImage;
            bool isDepthImage;
            WriteableBitmap player1;


            private void Window_Loaded(object sender, RoutedEventArgs e)
            {
                isDepthImage = false;
                //UseDepthAndPlayerIndex and UseSkeletalTracking
                kinect.Initialize(RuntimeOptions.UseDepthAndPlayerIndex | RuntimeOptions.UseColor);// | RuntimeOptions.UseSkeletalTracking);

                //register for event
                kinect.VideoFrameReady += new EventHandler(nui_VideoFrameReady);
                kinect.DepthFrameReady += new EventHandler(nui_DepthFrameReady);

                //Video image type
                kinect.VideoStream.Open(ImageStreamType.Video, 2, ImageResolution.Resolution640x480, 
                    ImageType.Color);

                //DepthAndPlayerIndex ImageType
                kinect.DepthStream.Open(ImageStreamType.Depth, 2, ImageResolution.Resolution320x240,
                    ImageType.DepthAndPlayerIndex);

            }

            void nui_VideoFrameReady(object sender, ImageFrameReadyEventArgs e)
            {
                colorImage = e.ImageFrame.Image;
                image1.Source = BitmapSource.Create(colorImage.Width, colorImage.Height, 96, 96,
                    PixelFormats.Bgr32, null, colorImage.Bits, colorImage.Width * colorImage.BytesPerPixel);

                if (isDepthImage)
                {
                    player1 = GeneratePlayerImage(e.ImageFrame, 1);
                    image3.Source = player1;
                }
            }

            void nui_DepthFrameReady(object sender, ImageFrameReadyEventArgs e)
            {
                //Convert depth information for a pixel into color information
                byte[] ColoredBytes = GenerateColoredBytes(e.ImageFrame);

                depthImage = e.ImageFrame.Image;
                image2.Source = BitmapSource.Create(depthImage.Width, depthImage.Height, 96, 96, PixelFormats.Bgr32, null,
                    ColoredBytes, depthImage.Width * PixelFormats.Bgr32.BitsPerPixel/8);

                isDepthImage = true;
            }

            private WriteableBitmap GeneratePlayerImage(ImageFrame imageFrame, int playerIndex)
            {
                int depthWidth = kinect.DepthStream.Width;
                int depthHeight = kinect.DepthStream.Height;

                WriteableBitmap target = new WriteableBitmap(depthWidth, depthHeight, 96, 96, PixelFormats.Bgra32, null);
                var depthRect = new System.Windows.Int32Rect(0, 0, depthWidth, depthHeight);

                byte[] color = imageFrame.Image.Bits;

                byte[] output = new byte[depthWidth * depthHeight * 4];

                //loop over each pixel in the depth image
                int outputIndex = 0;
                for (int depthY = 0, depthIndex = 0; depthY < depthHeight; depthY++)
                {
                    for(int depthX = 0; depthX < depthWidth; depthX++, depthIndex +=2)
                    {

                        short depthValue = (short)(depthImage.Bits[depthIndex] | (depthImage.Bits[depthIndex + 1] << 8));

                        int colorX, colorY;
                        kinect.NuiCamera.GetColorPixelCoordinatesFromDepthPixel(
                            imageFrame.Resolution,
                            imageFrame.ViewArea,
                            depthX, depthY, //depth coordinate
                            depthValue,     //depth value
                            out colorX, out colorY); //color coordinate

                        //ensure that the calculate color location is within the bounds of the image
                        colorX = Math.Max(0, Math.Min(colorX, imageFrame.Image.Width - 1));
                        colorY = Math.Max(0, Math.Min(colorY, imageFrame.Image.Height - 1));

                        output[outputIndex++] = color[(4 * (colorX + (colorY * imageFrame.Image.Width))) + 0];
                        output[outputIndex++] = color[(4 * (colorX + (colorY * imageFrame.Image.Width))) + 1];
                        output[outputIndex++] = color[(4 * (colorX + (colorY * imageFrame.Image.Width))) + 2];
                        output[outputIndex++] = GetPlayerIndex(depthImage.Bits[depthIndex]) == playerIndex ? (byte)255 : (byte)0;
                    }
                }
                target.WritePixels(depthRect, output, depthWidth * PixelFormats.Bgra32.BitsPerPixel/8, 0);
                return target;
                //return output;
            }

            private static int GetPlayerIndex(byte firstFrame)
            {
                //returns 0 = no player, 1 = 1st player, 2 = 2nd player...
                //bitwise & on firstFrame
                return (int)firstFrame & 7;
            }
        }
}

- 編集1-

私は問題を絞り込んだと思うが、それを解決する方法は不明だ。私はkinectの視野に1人しかいないと、私の "GetPlayerIndex"メソッドから1の値を返すと仮定しました。これはそうではありません。背景を取り除いた人物ごとに別々のイメージを作りたいと思っていました。私が受け取るべき値のタイプ:

- 編集2-

私のテストから、私はプレーヤーのインデックスの最大値は6になることに気付きましたが、私が得たインデックスは一貫していません。どのプレイヤーのインデックスがスケルトンに割り当てられるのか知る方法があれば?たとえば、私が唯一の邦人だったら、自分の選手インデックスが常に1であることを知る方法がありますか?

1
だから、あなたが言うところの元のコードは、 "改善の余地が十分にある"と言っているが、十分ではない?それとも、それはあなたの側で作者の元のコードとは異なった振る舞いをしていますか?
追加された 著者 Bart,
より具体的で狭いスコープの質問をここで定義できますか?それが立てば、私はあなたが "このコードを修正してください"と言っていると思います。これは実際には問題ではなく、潜在的にも非常に広いです。
追加された 著者 Flexo,
このリンクを参照することができます stackoverflow.com/questions/6844697/…
追加された 著者 ravithejag,

1 答え

プレーヤーのインデックスは何も保証されていません。スケルトンをキャッチすると、そのスケルトンが見えなくなるまでインデックスは同じままになりますが、最初のプレイヤーが1で、2番目のプレイヤーが2であると仮定することはできません。

あなたがする必要があることは、 player1 = GeneratePlayerImage(e.ImageFrame、1); コールの前に有効なスケルトンインデックスを決定するか、またはGeneratePlayerImage関数を変更してインデックスを見つけることです。背景を取り除き、フレーム内のすべての人々のピクセルをそのままにしたい場合は、これを変更してください:

output[outputIndex++] = GetPlayerIndex(depthImage.Bits[depthIndex]) == playerIndex ? (byte)255 : (byte)0;

特定のプレイヤーではなく、どんなプレイヤーかをチェックするだけです。

output[outputIndex++] = GetPlayerIndex(depthImage.Bits[depthIndex]) != 0 ? (byte)255 : (byte)0;

私が考えることができる他の2つの方法は、すべてのプレーヤーではなく特定のプレーヤーのためにこれを行うことです。

  1. Kinectのスケルトンフィードを開き、有効なインデックスを見つけるためのスケルトンの配列をループします。このインデックスを保持するグローバル整数を作成し、このグローバル整数でGeneratePlayerImageメソッドを呼び出します。
  2. 各ピクセルのプレーヤーインデックスを確認するGeneratePlayerImageメソッドを変更し、見つかった場合はそのインデックスを使用して画像全体の背景を削除します(見つかった他のインデックスは無視します)。
2
追加された