2016-03-21 9 views
0

Kinect 2を使用して、一部のモデルから3Dデータを取得してMatlabで処理できるようにしたいとします。基本的には、Kinectによって測定された点のXYZ座標を持つ3列のファイルです。連続したビデオは必要ありません。ボタンをクリックするたびに3Dポイントの1つの「イメージ」で十分です。Kinect 2の3Dデータを.txtファイルに保存

SDKには、画像としてデータを保存するサンプルコードが用意されています(Depth Basics-WPF)。私がしたいのは、データを生の数字として.txtファイルに保存することだけです。 C#を初めて使用しているので、私はそれを行う方法を見つけることができません。 Googleで見つかった別のコードを使って保存しようとしましたが、うまくいきません。

次のように提供されているコードの保存部分は次のとおりです。

/// <summary> 
    /// Handles the user clicking on the screenshot button 
    /// </summary> 
    /// <param name="sender">object sending the event</param> 
    /// <param name="e">event arguments</param> 
    private void ScreenshotdataButton_Click(object sender, RoutedEventArgs e) 
    { 
     if (this.depthBitmap != null) 
     { 
      // create a png bitmap encoder which knows how to save a .png file 
      BitmapEncoder encoder = new PngBitmapEncoder(); 

      // create frame from the writable bitmap and add to encoder 
      encoder.Frames.Add(BitmapFrame.Create(this.depthBitmap)); 

      string time = System.DateTime.UtcNow.ToString("hh'-'mm'-'ss", CultureInfo.CurrentUICulture.DateTimeFormat); 

      string myPhotos = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures); 

      string path = Path.Combine(myPhotos, "KinectScreenshot-Depth-" + time + ".png"); 

      // write the new file to disk 
      try 
      { 
       // FileStream is IDisposable 
       using (FileStream fs = new FileStream(path, FileMode.Create)) 
       { 
        encoder.Save(fs); 
       } 

       this.StatusText = string.Format(CultureInfo.CurrentCulture, Properties.Resources.SavedScreenshotStatusTextFormat, path); 
      } 
      catch (IOException) 
      { 
       this.StatusText = string.Format(CultureInfo.CurrentCulture, Properties.Resources.FailedScreenshotStatusTextFormat, path); 
      } 
     } 
    } 

私がターゲットとしてtxtファイルにコードを再利用しようとした:

string datapath = Path.Combine(myPhotos, "KinectScreenshot-Depth-" + time + ".txt"); 
// FileStream is IDisposable 
using (FileStream fs = new FileStream(datapath, FileMode.Create)) 
{ 
    //File.WriteAllBytes(datapath, depthPixels); 
    File.WriteAllText(datapath, depthRaw); 
} 

これが動作しない、ので、名前 'depthRaw'は現在のコンテキストに存在しません。

私はGoogleで見つかったコードで他の方法を試しました。

版1

public static Byte[] ImageToByteArray(Image img) 
    { 
     try 
     { 
      MemoryStream mstImage = new MemoryStream(); 
      img.Save(mstImage, System.Drawing.Imaging.ImageFormat.Jpeg); 
      Byte[] bytImage = mstImage.GetBuffer(); 
      return bytImage; 
     } 
     catch (Exception ex) 
     { 
      return null; 
     } 
    } 

版2

public static byte[] ConvertToByteArray(WriteableBitmap writeableBitmap) 
    { 
     using (var ms = new MemoryStream()) 
     { 
      writeableBitmap.SaveJpeg(ms, writeableBitmap.PixelWidth, writeableBitmap.PixelHeight, 0, 100); 
      return ms.ToArray(); 
     } 
    } 

版3

private byte[] ImageToByteArray (WriteableBitmap wbm) 
    { 
     using (Stream stream = wbm.PixelBuffer.AsStream()) 
     using (MemoryStream memoryStream = new MemoryStream()) 
     { 
      stream.CopyTo(memoryStream); 
      return memoryStream.ToArray(); 
     } 
    } 

版4

string bitmapString = null; 
    using (MemoryStream memoryStream = new MemoryStream()) 
    { 
     depthBitmap.Save(memoryStream, ImageFormat.png); 
     byte[] bitmapBytes = memoryStream.GetBuffer(); 
     bitmapString = Convert.ToBase64String(bitmapBytes, Base64FormattingOptions.InsertLineBreaks); 
    } 

名前空間 'Imaging'の名前空間が 'System.Drawing'に存在しません(アセンブリ参照がありません)または'WriteableBitmap'という名前の型が存在するため、 'PixelBuffer'/'SaveJpeg'/'Save'の定義がなく、 'WriteableBitmap'タイプの最初の引数を受け入れる拡張メソッド 'PixelBuffer'/'SaveJpeg'/'Save'が見つかりませんでした。指令またはアセンブリ参照?)

私のプログラミング経験は、Cとアセンブラに限られています。たぶん私はちょうどC#のいくつかの明白な部分を見逃していますか?このプログラムは、Windows 8.1およびMatlab 2011bを搭載したWindows PC上のVisual Studio 2015のC#で作成されています。

編集:完全なコード

//------------------------------------------------------------------------------ 
// <copyright file="MainWindow.xaml.cs" company="Microsoft"> 
//  Copyright (c) Microsoft Corporation. All rights reserved. 
// </copyright> 
//------------------------------------------------------------------------------ 

namespace Microsoft.Samples.Kinect.DepthBasics 
{ 
    using System; 
    using System.ComponentModel; 
    using System.Diagnostics; 
    using System.Drawing; 
    using System.Globalization; 
    using System.IO; 
    using System.Text; 
    using System.Windows; 
    using System.Windows.Media; 
    using System.Windows.Media.Imaging; 
    using System.Runtime.InteropServices.WindowsRuntime; 
    using Microsoft.Kinect; 

    /// <summary> 
    /// Interaction logic for MainWindow 
    /// </summary> 
    public partial class MainWindow : Window, INotifyPropertyChanged 
    { 
     /// <summary> 
     /// Map depth range to byte range 
     /// </summary> 
     private const int MapDepthToByte = 8000/256; 

     /// <summary> 
     /// Active Kinect sensor 
     /// </summary> 
     private KinectSensor kinectSensor = null; 

     /// <summary> 
     /// Reader for depth frames 
     /// </summary> 
     private DepthFrameReader depthFrameReader = null; 

     /// <summary> 
     /// Description of the data contained in the depth frame 
     /// </summary> 
     private FrameDescription depthFrameDescription = null; 

     /// <summary> 
     /// Bitmap to display 
     /// </summary> 
     private WriteableBitmap depthBitmap = null; 

     /// <summary> 
     /// Intermediate storage for frame data converted to color 
     /// </summary> 
     private byte[] depthPixels = null; 

     /// <summary> 
     /// Current status text to display 
     /// </summary> 
     private string statusText = null; 

     /// <summary> 
     /// Initializes a new instance of the MainWindow class. 
     /// </summary> 
     public MainWindow() 
     { 
      // get the kinectSensor object 
      this.kinectSensor = KinectSensor.GetDefault(); 

      // open the reader for the depth frames 
      this.depthFrameReader = this.kinectSensor.DepthFrameSource.OpenReader(); 

      // wire handler for frame arrival 
      this.depthFrameReader.FrameArrived += this.Reader_FrameArrived; 

      // get FrameDescription from DepthFrameSource 
      this.depthFrameDescription = this.kinectSensor.DepthFrameSource.FrameDescription; 

      // allocate space to put the pixels being received and converted 
      this.depthPixels = new byte[this.depthFrameDescription.Width * this.depthFrameDescription.Height]; 

      // create the bitmap to display 
      this.depthBitmap = new WriteableBitmap(this.depthFrameDescription.Width, this.depthFrameDescription.Height, 96.0, 96.0, PixelFormats.Gray8, null); 

      // set IsAvailableChanged event notifier 
      this.kinectSensor.IsAvailableChanged += this.Sensor_IsAvailableChanged; 

      // open the sensor 
      this.kinectSensor.Open(); 

      // set the status text 
      this.StatusText = this.kinectSensor.IsAvailable ? Properties.Resources.RunningStatusText 
                  : Properties.Resources.NoSensorStatusText; 

      // use the window object as the view model in this simple example 
      this.DataContext = this; 

      // initialize the components (controls) of the window 
      this.InitializeComponent(); 
     } 

     /// <summary> 
     /// INotifyPropertyChangedPropertyChanged event to allow window controls to bind to changeable data 
     /// </summary> 
     public event PropertyChangedEventHandler PropertyChanged; 

     /// <summary> 
     /// Gets the bitmap to display 
     /// </summary> 
     public ImageSource ImageSource 
     { 
      get 
      { 
       return this.depthBitmap; 
      } 
     } 

     /// <summary> 
     /// Gets or sets the current status text to display 
     /// </summary> 
     public string StatusText 
     { 
      get 
      { 
       return this.statusText; 
      } 

      set 
      { 
       if (this.statusText != value) 
       { 
        this.statusText = value; 

        // notify any bound elements that the text has changed 
        if (this.PropertyChanged != null) 
        { 
         this.PropertyChanged(this, new PropertyChangedEventArgs("StatusText")); 
        } 
       } 
      } 
     } 

     /// <summary> 
     /// Execute shutdown tasks 
     /// </summary> 
     /// <param name="sender">object sending the event</param> 
     /// <param name="e">event arguments</param> 
     private void MainWindow_Closing(object sender, CancelEventArgs e) 
     { 
      if (this.depthFrameReader != null) 
      { 
       // DepthFrameReader is IDisposable 
       this.depthFrameReader.Dispose(); 
       this.depthFrameReader = null; 
      } 

      if (this.kinectSensor != null) 
      { 
       this.kinectSensor.Close(); 
       this.kinectSensor = null; 
      } 
     } 

     /// <summary> 
     /// Handles the user clicking on the screenshot button 
     /// </summary> 
     /// <param name="sender">object sending the event</param> 
     /// <param name="e">event arguments</param> 
     private void ScreenshotButton_Click(object sender, RoutedEventArgs e) 
     { 
      if (this.depthBitmap != null) 
      { 
       // create a png bitmap encoder which knows how to save a .png file 
       BitmapEncoder encoder = new PngBitmapEncoder(); 

       // create frame from the writable bitmap and add to encoder 
       encoder.Frames.Add(BitmapFrame.Create(this.depthBitmap)); 

       string time = System.DateTime.UtcNow.ToString("hh'-'mm'-'ss", CultureInfo.CurrentUICulture.DateTimeFormat); 

       string myPhotos = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures); 

       string path = Path.Combine(myPhotos, "KinectScreenshot-Depth-" + time + ".png"); 

       // write the new file to disk 
       try 
       { 
        // FileStream is IDisposable 
        using (FileStream fs = new FileStream(path, FileMode.Create)) 
        { 
         encoder.Save(fs); 
        } 

        this.StatusText = string.Format(CultureInfo.CurrentCulture, Properties.Resources.SavedScreenshotStatusTextFormat, path); 
       } 
       catch (IOException) 
       { 
        this.StatusText = string.Format(CultureInfo.CurrentCulture, Properties.Resources.FailedScreenshotStatusTextFormat, path); 
       } 
      } 
     } 

     /*public static Byte[] ImageToByteArray(Image img) 
     { 
      try 
      { 
       MemoryStream mstImage = new MemoryStream(); 
       img.Save(mstImage, System.Drawing.Imaging.ImageFormat.Jpeg); 
       Byte[] bytImage = mstImage.GetBuffer(); 
       return bytImage; 
      } 
      catch (Exception ex) 
      { 
       return null; 
      } 
     }*/ 

     /*public static byte[] ConvertToByteArray(WriteableBitmap writeableBitmap) 
     { 
      using (var ms = new MemoryStream()) 
      { 
       writeableBitmap.SaveJpeg(ms, writeableBitmap.PixelWidth, writeableBitmap.PixelHeight, 0, 100); 
       return ms.ToArray(); 
      } 
     }*/ 

     /*private byte[] ImageToByteArray (WriteableBitmap wbm) 
     { 
      using (Stream stream = wbm.PixelBuffer.AsStream()) 
      using (MemoryStream memoryStream = new MemoryStream()) 
      { 
       stream.CopyTo(memoryStream); 
       return memoryStream.ToArray(); 
      } 
     }*/ 


     /*byte[] ConvertBitmapToByteArray(WriteableBitmap bitmap) 
     { 
      using (Stream stream = bitmap.PixelBuffer.AsStream()) 
      using (MemoryStream memoryStream = new MemoryStream()) 
      { 
       stream.CopyTo(memoryStream); 
       return memoryStream.ToArray(); 
      } 
     }*/ 

     /*string bitmapString = null; 
     using (MemoryStream memoryStream = new MemoryStream()) 
     { 
     depthBitmap.Save(memoryStream, ImageFormat.png); 
     byte[] bitmapBytes = memoryStream.GetBuffer(); 
     bitmapString = Convert.ToBase64String(bitmapBytes, Base64FormattingOptions.InsertLineBreaks); 
     }*/ 

     /// <summary> 
     /// Handles the user clicking on the screenshot button 
     /// </summary> 
     /// <param name="sender">object sending the event</param> 
     /// <param name="e">event arguments</param> 
     private void ScreenshotdataButton_Click(object sender, RoutedEventArgs e) 
     { 
      if (this.depthBitmap != null) 
      { 
       WriteableBitmap deschd = this.depthBitmap; 

       // create a png bitmap encoder which knows how to save a .png file 
       BitmapEncoder encoder = new PngBitmapEncoder(); 

       // create frame from the writable bitmap and add to encoder 
       encoder.Frames.Add(BitmapFrame.Create(this.depthBitmap)); 

       string time = System.DateTime.UtcNow.ToString("hh'-'mm'-'ss", CultureInfo.CurrentUICulture.DateTimeFormat); 

       string myPhotos = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures); 

       string path = Path.Combine(myPhotos, "KinectScreenshot-Depth-" + time + ".png"); 

       string datapath = Path.Combine(myPhotos, "KinectScreenshot-Depth-" + time + ".txt"); 

       // write the new file to disk 
       try 
       { 
        // FileStream is IDisposable 
        using (FileStream fs = new FileStream(path, FileMode.Create)) 
        { 
         encoder.Save(fs); 
        } 

        this.StatusText = string.Format(CultureInfo.CurrentCulture, Properties.Resources.SavedScreenshotStatusTextFormat, path); 
       } 
       catch (IOException) 
       { 
        this.StatusText = string.Format(CultureInfo.CurrentCulture, Properties.Resources.FailedScreenshotStatusTextFormat, path); 
       } 

       // raw data 

       //string depthRaw = Encoding.UTF8.GetString(this.depthPixels); 
       string depthRaw = this.depthPixels.ToString(); 

       // write the txt file to disk with the raw data 
       try 
       { 
        // FileStream is IDisposable 
        using (FileStream fs = new FileStream(datapath, FileMode.Create)) 
        { 
         //File.WriteAllBytes(datapath, depthPixels); 
         File.WriteAllText(datapath, depthRaw); 
        } 

        this.StatusText = string.Format(CultureInfo.CurrentCulture, Properties.Resources.SavedScreenshotStatusTextFormat, datapath); 
       } 
       catch (IOException) 
       { 
        this.StatusText = string.Format(CultureInfo.CurrentCulture, Properties.Resources.FailedScreenshotStatusTextFormat, datapath); 
       } 
      } 
     } 

     /// <summary> 
     /// Handles the depth frame data arriving from the sensor 
     /// </summary> 
     /// <param name="sender">object sending the event</param> 
     /// <param name="e">event arguments</param> 
     private void Reader_FrameArrived(object sender, DepthFrameArrivedEventArgs e) 
     { 
      bool depthFrameProcessed = false; 

      using (DepthFrame depthFrame = e.FrameReference.AcquireFrame()) 
      { 
       if (depthFrame != null) 
       { 
        // the fastest way to process the body index data is to directly access 
        // the underlying buffer 
        using (Microsoft.Kinect.KinectBuffer depthBuffer = depthFrame.LockImageBuffer()) 
        { 
         // verify data and write the color data to the display bitmap 
         if (((this.depthFrameDescription.Width * this.depthFrameDescription.Height) == (depthBuffer.Size/this.depthFrameDescription.BytesPerPixel)) && 
          (this.depthFrameDescription.Width == this.depthBitmap.PixelWidth) && (this.depthFrameDescription.Height == this.depthBitmap.PixelHeight)) 
         { 
          // Note: In order to see the full range of depth (including the less reliable far field depth) 
          // we are setting maxDepth to the extreme potential depth threshold 
          ushort maxDepth = ushort.MaxValue; 

          // If you wish to filter by reliable depth distance, uncomment the following line: 
          //// maxDepth = depthFrame.DepthMaxReliableDistance 

          this.ProcessDepthFrameData(depthBuffer.UnderlyingBuffer, depthBuffer.Size, depthFrame.DepthMinReliableDistance, maxDepth); 
          depthFrameProcessed = true; 
         } 
        } 
       } 
      } 

      if (depthFrameProcessed) 
      { 
       this.RenderDepthPixels(); 
      } 
     } 

     /// <summary> 
     /// Directly accesses the underlying image buffer of the DepthFrame to 
     /// create a displayable bitmap. 
     /// This function requires the /unsafe compiler option as we make use of direct 
     /// access to the native memory pointed to by the depthFrameData pointer. 
     /// </summary> 
     /// <param name="depthFrameData">Pointer to the DepthFrame image data</param> 
     /// <param name="depthFrameDataSize">Size of the DepthFrame image data</param> 
     /// <param name="minDepth">The minimum reliable depth value for the frame</param> 
     /// <param name="maxDepth">The maximum reliable depth value for the frame</param> 
     private unsafe void ProcessDepthFrameData(IntPtr depthFrameData, uint depthFrameDataSize, ushort minDepth, ushort maxDepth) 
     { 
      // depth frame data is a 16 bit value 
      ushort* frameData = (ushort*)depthFrameData; 

      // convert depth to a visual representation 
      for (int i = 0; i < (int)(depthFrameDataSize/this.depthFrameDescription.BytesPerPixel); ++i) 
      { 
       // Get the depth for this pixel 
       ushort depth = frameData[i]; 

       // To convert to a byte, we're mapping the depth value to the byte range. 
       // Values outside the reliable depth range are mapped to 0 (black). 
       this.depthPixels[i] = (byte)(depth >= minDepth && depth <= maxDepth ? (depth/MapDepthToByte) : 0); 
      } 
     } 

     /// <summary> 
     /// Renders color pixels into the writeableBitmap. 
     /// </summary> 
     private void RenderDepthPixels() 
     { 
      this.depthBitmap.WritePixels(
       new Int32Rect(0, 0, this.depthBitmap.PixelWidth, this.depthBitmap.PixelHeight), 
       this.depthPixels, 
       this.depthBitmap.PixelWidth, 
       0); 
     } 

     /// <summary> 
     /// Handles the event which the sensor becomes unavailable (E.g. paused, closed, unplugged). 
     /// </summary> 
     /// <param name="sender">object sending the event</param> 
     /// <param name="e">event arguments</param> 
     private void Sensor_IsAvailableChanged(object sender, IsAvailableChangedEventArgs e) 
     { 
      // on failure, set the status text 
      this.StatusText = this.kinectSensor.IsAvailable ? Properties.Resources.RunningStatusText 
                  : Properties.Resources.SensorNotAvailableStatusText; 
     } 

     private void Button_Click(object sender, RoutedEventArgs e) 
     { 

     } 
    } 
} 
+0

私の経験上、Kinect SDKは深度値に直接アクセスできるため、画像からバイトを取得する必要はありません – Domysee

+0

完全なコードを入力してください...'using'ステートメントをicludingすると、私はあなたがいくつかのDLLを失っていると思います。 –

+0

@Domysee実際に深度データを直接取得する方法については説明がありますが、最終的には画像として保存することになります。 https://msdn.microsoft.com/en-us/library/jj131029.aspx# CS_GetData –

答えて

0

私は回避策を見つけました。

private unsafe void ProcessDepthFrameData(IntPtr depthFrameData, uint depthFrameDataSize, ushort minDepth, ushort maxDepth) 
{ 
    // depth frame data is a 16 bit value 
    ushort* frameData = (ushort*)depthFrameData; 

    int colorIndex = 0; 

    // convert depth to a visual representation 
    for (int i = 0; i < (int)(depthFrameDataSize/this.depthFrameDescription.BytesPerPixel); ++i) 
    { 
     // Get the depth for this pixel 
     ushort depth = frameData[i]; 

     this.distanceImage[colorIndex++] = (byte)(depth >> 8); // how many times can the intensity be divided by 256? 
     this.distanceImage[colorIndex++] = (byte)(depth - ((depth >> 8) << 8)); // remainder after the division 
     this.distanceImage[colorIndex++] = (byte)(0); 
     this.distanceImage[colorIndex++] = (byte)(255); 

     // To convert to a byte, we're mapping the depth value to the byte range. 
     // Values outside the reliable depth range are mapped to 0 (black). 
     this.depthPixels[i] = (byte)(depth >= minDepth && depth <= maxDepth ? (depth/MapDepthToByte) : 0); 
    } 
} 

これは、その後、カラーPNGとして保存されます。カラー画像は、データを格納するための複数のバイトを持っているという事実を使用して、私はグレースケールの大きさ「拡大します」。 Matlabでは、pngがロードされ、逆変換が実行されて、全体の範囲の深度値を持つ1つの行列が得られます。

関連する問題