【问题标题】:Kinect background removalKinect 背景去除
【发布时间】:2011-11-12 21:41:44
【问题描述】:

我遵循了 Robert Levy 在此链接中提供的代码: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<ImageFrameReadyEventArgs>(nui_VideoFrameReady);
                kinect.DepthFrameReady += new EventHandler<ImageFrameReadyEventArgs>(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 的视野中只有一个人会从我的“GetPlayerIndex”方法返回一个值。不是这种情况。我希望为每个人制作一个单独的图像,背景被移除。我应该假设从什么类型的值接收:

-编辑2-

从我的测试中,我注意到玩家索引的最大值可以为 6,但我得到的索引并不一致。如果有办法知道将分配给骨架的玩家索引是什么?例如,如果我是 fov 中唯一的人,是否有办法知道我的玩家索引始终为 1?

【问题讨论】:

  • 所以你是说作者说“还有很多改进空间”的原始代码是不够的?或者它在你这边的行为与作者的原始代码不同?
  • 您能在这里定义一个更具体、范围更窄的问题吗?就目前而言,我认为您是在说“请修复此代码”,这实际上不是一个问题,而且可能也很广泛。
  • 可以参考这个链接stackoverflow.com/questions/6844697/…

标签: kinect


【解决方案1】:

不保证玩家索引是任何东西。一旦它抓住了一个骷髅,该骷髅的索引将保持不变,直到它看不见它,但你不能假设第一个玩家是 1,第二个玩家是 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;

我能想到的其他两种方法可以针对特定玩家而不是所有玩家:

  1. 打开 Kinect 的 Skeleton 提要,并循环遍历它为您提供的骨架数组以找到有效索引。创建一个全局整数来保存这个索引,然后用这个全局整数调用 GeneratePlayerImage 方法。
  2. 更改 GeneratePlayerImage 方法以检查每个像素中的玩家索引,如果找到,则使用该索引删除整个图像的背景(忽略它找到的任何其他索引)。

【讨论】:

    猜你喜欢
    • 2017-11-14
    • 1970-01-01
    • 2017-03-27
    • 2015-05-05
    • 1970-01-01
    • 1970-01-01
    • 2011-11-10
    • 2016-02-19
    • 1970-01-01
    相关资源
    最近更新 更多