2011-11-12 52 views
-1

我跟着羅伯特·利維在這個環節提供的代碼:http://channel9.msdn.com/coding4fun/kinect/Display-Kinect-color-image-containing-only-players-aka-background-removalKinect的背景去除

我試圖推行它放到我現有的代碼,併產生了不一致的結果。如果用戶在程序啓動時處於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玩家指數最大值,但我得到ISN指數不一致。如果有辦法知道什麼玩家指數將被分配給骨架?例如,如果我是fov中唯一的人,是否有辦法知道我的玩家指數總是1?

+2

所以你說的是作者說的「有很大的改進空間」的原始代碼是不夠的?或者它的表現與作者的原始代碼不同? – Bart

+0

您能在這裏定義一個更具體,更狹窄的範圍問題嗎?按照我的觀點,我想你說的是「請修復此代碼」,這實際上不是一個問題,而且可能也非常廣泛。 – Flexo

+1

你可以參考這個鏈接http://stackoverflow.com/questions/6844697/how-to-align-kinects-depth-image-with-color-image – ravithejag

回答

2

玩家指數不保證是任何東西。一旦它捕捉到一個骷髏,該索引將保持不變,直到它失去它的視覺,但你不能假設第一個玩家將是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的骨架飼料,並遍歷骨架給它的陣列你找到一個有效的索引。創建一個全局整數來保存這個索引,然後用這個全局整數調用GeneratePlayerImage方法。
  2. 更改GeneratePlayerImage方法以檢查每個像素中的播放器索引,並且如果找到該索引,則使用該索引刪除整個圖像的背景(忽略其找到的任何其他索引)。