none
How to save XYZ-data to textfile? RRS feed

  • Question

  • Hi

    I'm totally new to C# and need some help.

    I would like to save a textfile with the X,Y, and Z data in three columns. The file should be saved
    for example when a key is pressed and I would like to incorporate this function into the Skeletal Viewer-example.

    I guess I should use the "SkeletonEngine.DepthImageToSkeleton"-function but I don't understand how.

    Could someone please write those few lines of code for me?

    /Tobias

    Monday, July 25, 2011 12:09 PM

Answers

  • Thanks Eddy. Now it works.
    Below is an example of how to write XYZ in three columns to a textfile: 

     

    StreamWriter writer = new StreamWriter("myfile.txt");
    writer.WriteLine("X Y Z");
    for (int i = 0; i < Image.Bits.Length; i += 2)
    {
    	int depthPixel = (Image.Bits[i+1] << 8) | Image.Bits[i];
    	int x = (i/2) % 320; // Because image width is 320 pixels
    	int y = (i/2) / 320;
    
    	Microsoft.Research.Kinect.Nui.Vector realWorldPos = 
    		nui.SkeletonEngine.DepthImageToSkeleton(((float)x)/320.0f, ((float)y)/240.0f, (short)depthPixel);
    	
    	// Store value of realWorldPos
    	writer.WriteLine(realWorldPos.X +" "+ realWorldPos.Y +" "+ realWorldPos.Z);
    }
    writer.Close();
    Thursday, August 4, 2011 6:36 AM

All replies

  • using (StreamWriter writer = new StreamWriter("myfile.txt")
    {
      writer.Write("X=");
      writer.WriteLine(x);
    }
    


    That shows the basics of writing to a file. Write is overloaded to write any of the base types as text. WriteLine starts a new line after writing the specified value. That isn't a recomendation for format. Personally if I were going to import it as csv into Excel I would just write the depth value 640/320 values to a row seperated by "," or tabs and 480/240 rows. The pixel coordinate can be implied by the row and column it's in.

    You can get the skeleton space (x,y,z) by (x/focalLength*depth,y/focalLength*depth,depth) with x=sx-width/2 and y=height/2-sy so that (0,0) is the center of the screen. So you don't need to pass the x and y values. You might want to put in a row at the start with width and height to make it easier to work with.

    Overall what format depends upon what you're going to do with the data. Importing into Excel is one example. With some things writing a bitmap would be better. The above though gives you basically how to write a text file. You have to figure out what text you would prefer to write.

    Monday, July 25, 2011 4:15 PM
  • Are x and y the pixel indices?

    What is the focal length?


    Tuesday, July 26, 2011 11:05 AM
  • yes, x and y are depth image pixel indices. Focal length is defined in MSR_NuiImageCamera.h (an SDK header), as

     

    #define NUI_CAMERA_DEPTH_NOMINAL_FOCAL_LENGTH_IN_PIXELS   (285.63f) // Based on 320x240 pixel size.
    

    You shouldn't need to bother with making calculation yourself, though, if you use SkeletonEngine.DepthImageToSkeleton method as you mentioned above. Starting from the SkeletalViewer sample (C:\Users\Public\Documents\Microsoft Research KinectSDK Samples\NUI\SkeletalViewer\CS), you could modify the nui_DepthFrameReady method to be:

     

     

    void nui_DepthFrameReady(object sender, ImageFrameReadyEventArgs e)
    {
     PlanarImage image = e.ImageFrame.Image;
     for (int i = 0; i < image.Bits.Length; i += 2)
     {
      int depthPixel = (image.Bits[i+1] << 8) | image.Bits[i];
      int x = (i/2) % 320; // Because image width is 320 pixels
      int y = (i/2) / 320;
    
       Microsoft.Research.Kinect.Nui.Vector realWorldPos = nui.SkeletonEngine.DepthImageToSkeleton(((float)x)/320.0f, ((float)y)/240.0f, depthPixel);
    
      // Store value of realWorldPos
     }
    }

    To be able to do this when user hits a keystroke, rather than for every frame, you could keep the last depth image frame in a buffer that you can access when you are doing the keystroke handling code, then do the DepthImageToSkeleton mapping there.

     

    Hope this helps,
    Eddy


    I'm here to help
    • Edited by Eddy Escardo-Raffo [MSFT] Tuesday, August 2, 2011 2:52 AM corrected first subscript of image.Bits to be "i+1" instead of just "i"
    Tuesday, July 26, 2011 8:12 PM
  • This sounds like what I might need. I am planning to import the x,y,z data into something like Excel(it uses .csv) Could you give me an example of the code? I'm lost and a newbie.
    Wednesday, July 27, 2011 3:59 AM
  • Ok. Thanks. Got the values now but they seem a bit strange. The Z-values are all over the place!? Spread out between 0 and 8 meters.
    I did it like this:

    // Write matrix to file if file does not exist
    if (!File.Exists("myfile.txt") && totalFrames == 100)
    {
    	StreamWriter writer = new StreamWriter("myfile.txt");
    	for (int i = 0; i < Image.Bits.Length; i += 2)
    	{
    		int depthPixel = (Image.Bits[i] << 8) | Image.Bits[i];
    		int x = (i/2) % 320; // Because image width is 320 pixels
    		int y = (i/2) / 320;
    
    		Microsoft.Research.Kinect.Nui.Vector realWorldPos = nui.SkeletonEngine.DepthImageToSkeleton(((float)x)/320.0f, ((float)y)/240.0f, (short)depthPixel);
    					
    		// Store value of realWorldPos
    		writer.WriteLine(realWorldPos.X + " " + realWorldPos.Y + " " + realWorldPos.Z);
    	}
    	writer.Close();
    }

    Wednesday, July 27, 2011 11:35 AM
  • Are you using depth stream (RuntimeOptions.UseDepth) or depth+player index (RuntimeOptions.UseDepthAndPlayerIndex) stream? If it's plain depth stream then actually you should left shift depthPixel value by 3 before calling DepthImageToSkeleton:

    Microsoft.Research.Kinect.Nui.Vector realWorldPos = nui.SkeletonEngine.DepthImageToSkeleton(((float)x)/320.0f, ((float)y)/240.0f, (short)(depthPixel<<3));
    


    Sorry I forgot to mention that. The DepthImageToSkeleton function uses this format since the lower 3 bits in depth+player index stream contain player index data.

    Does that resolve your problem? You should never see values larger than 4 meters, but it is expected that some values would be zero meters, since zero is returned for pixels that have depth below or above valid camera range (0.8-4.0 meters).
    Eddy


    I'm here to help
    Wednesday, July 27, 2011 6:32 PM
  • I'm using the Depth-and-Player stream since I just plugged in the above mentioned code into nui_DepthFrameReady in SkeletalViewer, so bit shifting depthPixel only made it worse. :(

    The depth data comes in almost discrete numbers, does that give you a hint?

    Monday, August 1, 2011 6:17 AM
  • I'm very sorry, I gave you code with one mistake. Instead of

    int depthPixel = (Image.Bits[i] << 8) | Image.Bits[i];
    

    it should be

    int depthPixel = (Image.Bits[i+1] << 8) | Image.Bits[i];
    

    (notice the "+ 1" in the first array indexing). I should have compiled and tested code before giving it to you. I've edited my original code sample to avoid others making the same mistake.

    Eddy


    I'm here to help
    Tuesday, August 2, 2011 2:51 AM
  • Thanks Eddy. Now it works.
    Below is an example of how to write XYZ in three columns to a textfile: 

     

    StreamWriter writer = new StreamWriter("myfile.txt");
    writer.WriteLine("X Y Z");
    for (int i = 0; i < Image.Bits.Length; i += 2)
    {
    	int depthPixel = (Image.Bits[i+1] << 8) | Image.Bits[i];
    	int x = (i/2) % 320; // Because image width is 320 pixels
    	int y = (i/2) / 320;
    
    	Microsoft.Research.Kinect.Nui.Vector realWorldPos = 
    		nui.SkeletonEngine.DepthImageToSkeleton(((float)x)/320.0f, ((float)y)/240.0f, (short)depthPixel);
    	
    	// Store value of realWorldPos
    	writer.WriteLine(realWorldPos.X +" "+ realWorldPos.Y +" "+ realWorldPos.Z);
    }
    writer.Close();
    Thursday, August 4, 2011 6:36 AM
  • What not get the SkeletonData.Joints's positions?
    akira32 編程之家 Yahoo http://tw.myblog.yahoo.com/akira32-akira32
    Thursday, August 4, 2011 4:31 PM