2013-03-15 5 views
1

Я новичок в Kinect и C#. Я пытаюсь получить изображение глубины с Kinect, преобразовать его в растровое изображение, чтобы выполнить некоторые операции OpenCV, а затем отобразить его. Проблема в том, что я получаю только треть изображения глубины, а остальная часть полностью черная (как видно на рисунке). Это не грубое изображение глубины, а изображение, которое я получаю после рисования.Kinect Depth Изображение только частично видимое

enter image description here

Вот код-

изображения и image1 являются холст два изображения я иметь для отображения.

void DepthFrameReady(object sender, DepthImageFrameReadyEventArgs e) 
    { 

     DepthImageFrame Image; 
     Bitmap bm; 
     using (Image = e.OpenDepthImageFrame()) 
     { 


      if (Image != null) 
      { 
      this.shortpixeldata = new short[Image.PixelDataLength]; 
      this.depthFrame32 = new byte[Image.Width * Image.Height * Bgr32BytesPerPixel]; 


      bmp = new Bitmap(Image.Width, Image.Height, System.Drawing.Imaging.PixelFormat.Format32bppRgb); 
      Image.CopyPixelDataTo(this.shortpixeldata); 

      byte[] convertedDepthBits = this.ConvertDepthFrame(this.shortpixeldata, ((KinectSensor)sender).DepthStream); 


      BitmapData bmapdata = bmp.LockBits(
           new System.Drawing.Rectangle(0, 0, Image.Width, Image.Height), 
           ImageLockMode.WriteOnly, 
           bmp.PixelFormat); 


      IntPtr ptr = bmapdata.Scan0; 
      Marshal.Copy(convertedDepthBits, 0, ptr, Image.PixelDataLength); 
      bmp.UnlockBits(bmapdata); 

      MemoryStream ms1 = new MemoryStream(); 
      bmp.Save(ms1, System.Drawing.Imaging.ImageFormat.Jpeg); 
      System.Windows.Media.Imaging.BitmapImage bImg = new System.Windows.Media.Imaging.BitmapImage(); 
      bImg.BeginInit(); 
      bImg.StreamSource = new MemoryStream(ms1.ToArray()); 
      bImg.EndInit(); 

      image.Source = bImg; 

       if (bmp != null) 
      { 

       Image<Bgr, Byte> currentFrame = new Image<Bgr, Byte>(bmp); 

       Image<Gray, Byte> grayImage = currentFrame.Convert<Gray, Byte>().PyrDown().PyrUp(); 
       Image<Gray, Byte> Dest = new Image<Gray, Byte>(grayImage.Size); 
       CvInvoke.cvCanny(grayImage, Dest, 10, 60, 3); 


       image1.Source = ToBitmapSource(Dest); 

       CalculateFps(); 
      } 



      } 



      else 
      { 
       System.Diagnostics.Debug.WriteLine("depth bitmap empty :/"); 
      } 
     } 
    } 


     private byte[] ConvertDepthFrame(short[] depthFrame, DepthImageStream depthStream) 
     { 
      System.Diagnostics.Debug.WriteLine("depthframe len :{0}", depthFrame.Length); 

     for (int i16 = 0, i32 = 0; i16 < depthFrame.Length && i32 < this.depthFrame32.Length; i16++, i32 += 4) 
     { 

     int realDepth = depthFrame[i16] >> DepthImageFrame.PlayerIndexBitmaskWidth; 


     byte Distance = 0; 


     int MinimumDistance = 800; 
     int MaximumDistance = 4096; 


     if (realDepth > MinimumDistance) 
     { 


     //White = Close 
     //Black = Far 
     Distance = (byte)(255-((realDepth-MinimumDistance)*255/(MaximumDistance-MinimumDistance))); 


     this.depthFrame32[i32 + RedIndex] = (byte)(Distance); 
     this.depthFrame32[i32 + GreenIndex] = (byte)(Distance); 
     this.depthFrame32[i32 + BlueIndex] = (byte)(Distance); 
     } 

     else 
     { 
     this.depthFrame32[i32 + RedIndex] = 0; 
     this.depthFrame32[i32 + GreenIndex] = 150; 
     this.depthFrame32[i32 + BlueIndex] = 0; 
     } 
     } 

     return this.depthFrame32; 
     } 

Я пробовал разные PixelFormats безрезультатно. Я не могу понять проблему. Кто-нибудь знает, что я делаю неправильно? Thanks

ответ

0

Хорошо, я понял это самостоятельно. Все это время скрывалось на виду.

Функция ConvertDepthFrame возвращает массив байтов в convertDepthBits разного размера (его 4 отдельных канала, поэтому 4 раза исходный размер), мне нужно использовать длину данных, которые нужно скопировать как 4 * Image.PixelDataLength в вызове метода : Marshal.Copy (...)

Работает отлично. Фу! :)

+0

Не забудьте принять ваш ответ, как только получите шанс. ;) – weberc2

0

Я бы предложил использовать WritableBitmap, чтобы скопировать изображение глубины в формат просмотра. В случае с PixelFormat эта информация доступна в самом изображении глубины, поэтому вы должны использовать тот же формат для WritableBitmap, который будет снят.

Вы посмотрели на любой из примеров, предоставленных Microsoft? Вы можете найти их на странице Kinect for Windows Samples CodePlex. Есть несколько примеров, которые демонстрируют, как скопировать данные глубины в WritableBitmap, а затем вывести их. Например, здесь есть функция DepthFrameReady обратного вызова образца приложения «DepthBasics-МОФ»:

/// <summary> 
/// Event handler for Kinect sensor's DepthFrameReady event 
/// </summary> 
/// <param name="sender">object sending the event</param> 
/// <param name="e">event arguments</param> 
private void SensorDepthFrameReady(object sender, DepthImageFrameReadyEventArgs e) 
{ 
    using (DepthImageFrame depthFrame = e.OpenDepthImageFrame()) 
    { 
     if (depthFrame != null) 
     { 
      // Copy the pixel data from the image to a temporary array 
      depthFrame.CopyDepthImagePixelDataTo(this.depthPixels); 

      // Get the min and max reliable depth for the current frame 
      int minDepth = depthFrame.MinDepth; 
      int maxDepth = depthFrame.MaxDepth; 

      // Convert the depth to RGB 
      int colorPixelIndex = 0; 
      for (int i = 0; i < this.depthPixels.Length; ++i) 
      { 
       // Get the depth for this pixel 
       short depth = depthPixels[i].Depth; 

       // To convert to a byte, we're discarding the most-significant 
       // rather than least-significant bits. 
       // We're preserving detail, although the intensity will "wrap." 
       // Values outside the reliable depth range are mapped to 0 (black). 

       // Note: Using conditionals in this loop could degrade performance. 
       // Consider using a lookup table instead when writing production code. 
       // See the KinectDepthViewer class used by the KinectExplorer sample 
       // for a lookup table example. 
       byte intensity = (byte)(depth >= minDepth && depth <= maxDepth ? depth : 0); 

       // Write out blue byte 
       this.colorPixels[colorPixelIndex++] = intensity; 

       // Write out green byte 
       this.colorPixels[colorPixelIndex++] = intensity; 

       // Write out red byte       
       this.colorPixels[colorPixelIndex++] = intensity; 

       // We're outputting BGR, the last byte in the 32 bits is unused so skip it 
       // If we were outputting BGRA, we would write alpha here. 
       ++colorPixelIndex; 
      } 

      // Write the pixel data into our bitmap 
      this.colorBitmap.WritePixels(
       new Int32Rect(0, 0, this.colorBitmap.PixelWidth, this.colorBitmap.PixelHeight), 
       this.colorPixels, 
       this.colorBitmap.PixelWidth * sizeof(int), 
       0); 
     } 
    } 
} 

Полный код для данного класса можно найти здесь: http://kinectforwindows.codeplex.com/SourceControl/changeset/view/861462899ae7#v1.x/ToolkitSamples1.6.0/C#/DepthBasics-WPF/MainWindow.xaml.cs

Пример «Kinect Explorer» является другой хороший обзор, поскольку он рассматривает все три потока сразу. Он требует библиотеки, которая не входит в репозиторий CodePlex, но может быть найдена в Kinect for Windows Toolkit.

+0

Мне нужно выполнить некоторые операции openCV на окрашенном _depthImage_, который работает с Bitmap. Обертка EmguCV для openCv не принимает _WritableBitmap_ AFAIK. Я решил проблему сейчас, хотя, спасибо за ваше время! :) – uvcyclotron