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)
{
}
}
}
私の経験上、Kinect SDKは深度値に直接アクセスできるため、画像からバイトを取得する必要はありません – Domysee
完全なコードを入力してください...'using'ステートメントをicludingすると、私はあなたがいくつかのDLLを失っていると思います。 –
@Domysee実際に深度データを直接取得する方法については説明がありますが、最終的には画像として保存することになります。 https://msdn.microsoft.com/en-us/library/jj131029.aspx# CS_GetData –