0

I have an array of CameraSpacePoint in C# programming language on Windows 10. The CameraSpacePoint have three float variables, and defined inside Microsoft SDK as follows:

using System;
using System.Diagnostics;

namespace Microsoft.Kinect
    public struct CameraSpacePoint : IEquatable<CameraSpacePoint>
    {
        public float X;
        public float Y;
        public float Z;
        public bool Equals(CameraSpacePoint point);
        public sealed override bool Equals(object obj);
        public sealed override int GetHashCode();
        public static bool operator ==(CameraSpacePoint a, CameraSpacePoint b);
        public static bool operator !=(CameraSpacePoint a, CameraSpacePoint b);
    }
}

I have serialized the array of CameraSpacePoint in C# by following this suggestion.

private int data_width  = 512;
private int data_height = 424;
private int data_size   = data_width * data_height; // 217088

var cameraSpacePoints = new CameraSpacePoint[data_size]; 
// fill the values in cameraSpacePoints here
var bytes = ObjectToByteArray(cameraSpacePoints);
Console.WriteLine(bytes.Length); //prints 4559058

The converted byte array is then transferred to Ubuntu.

In order to deserialize the byte array, first I designed a similar structure in C++ (Ubuntu) as follow:

struct CameraSpacePoint
{
    float X;
    float Y;
    float Z;
};

Now I am using memcpy(&cameraSpacePoints, data_buffer, data_size_bytes) to deserialize but it gives segmentation fault. I highly doubt that it is because of mismatching of array size in C++.

Below is the code snippet:

#include <ros/ros.h>
#include <boost/asio.hpp>

using boost::asio::ip::tcp;

constexpr size_t data_width        = 512;
constexpr size_t data_height       = 424;
constexpr size_t data_size         = data_width * data_height;
constexpr size_t data_size_bytes   = data_size * 3 * sizeof(float); // each point have three float variables i.e., X, Y and Z
unsigned char data_buffer[data_size_bytes];

CameraSpacePoint cameraSpacePoints[data_size];

boost::asio::io_service io_service;
tcp::resolver resolver(io_service);
tcp::resolver::iterator endpoint_iterator = resolver.resolve({server_host, server_port});

tcp::socket socket(io_service);
try
{
    boost::asio::connect(socket, endpoint_iterator);
}
catch (boost::system::system_error const& e)
{
    std::cout << "Failed to connect to server "<< server_host.c_str() <<":"<< server_port.c_str() << e.what() << std::endl;
    return -1;
}

while(ros::ok())
{
    boost::asio::read(socket, boost::asio::buffer(data_buffer, data_size_bytes));
    memcpy(&cameraSpacePoints, data_buffer, data_size_bytes);

    //CameraSpacePoint midPoint = cameraSpacePoints[data_size/2];
    //std::cout << ":{" << midPoint.X << "," << midPoint.Y << "," << midPoint.Z << "}" << std::endl;
    std::cout << "Data Received" << std::endl;
    boost::asio::write(socket, boost::asio::buffer("OK\n"));
    ros::spinOnce();
}

Please note that, if I comment memcpy command, Data Received is being printed on the terminal. But with memcpy, the program stops by throwing segmentation fault error.

ravi
  • 6,140
  • 18
  • 77
  • 154
  • My C++ is a little rusty, but isn't `cameraSpacePoints` already an array (thus already a pointer)? Shouldn't it be just: `memcpy(cameraSpacePoints, data_buffer, data_size_bytes);` – Ilian Nov 15 '17 at 04:52
  • @IlianPinzon: Make sense. Let me try it out quickly. Thank you very much for the finding. – ravi Nov 15 '17 at 05:05
  • @IlianPinzon: It didn't help. Though it was a mistake too. I updated the question. Can you please have a look again? – ravi Nov 15 '17 at 05:31
  • Encoding scheme is dependent from platform. I think it's not a good idea using memcopy between platforms. – Jake Nov 15 '17 at 06:06
  • @Jake: Agree. However, I tried to serialize and deserialize image (Bitmap format) and it worked well, with the same approach. How to deserialize the above object simply? – ravi Nov 15 '17 at 06:12
  • I think the memory stream is the other way. It's a variable. I think the memory placement of variable may be differ from memory stream, like BItmap. – Jake Nov 15 '17 at 06:47
  • How about try a test , make a CameraSpacePoint class with same value both windows and linux and save it to file. Then compare files. If the contents and the size is wrong then we need find another way. If same, we dont warry about the platform and continue to find a way. – Jake Nov 15 '17 at 07:38
  • @Jake: Thanks a lot. I forgot to tell you that in case of image data, I needed to flip the image. Please see below the code snippet: `constexpr size_t image_size = image_width * image_height * 3; // 24-bit RGB image unsigned char frame_buffer[image_size]; cv::Mat image(cv::Size(image_width, image_height), CV_8UC3, frame_buffer); boost::asio::read(socket, boost::asio::buffer(frame_buffer, frame_size)); cv::flip(image, image, 1);` – ravi Nov 15 '17 at 09:46
  • @Jake: What do you mean by **save CameraSapcePoint to a file**? `CameraSpacePoint` in C# is designed by Microsoft (Although I can make my own class with the same name ). I couldn't understand **file compassion** too. Can you please explain your above comment in detail? Always thanks. – ravi Nov 15 '17 at 09:49
  • Yeah, that's right. Let's try save that class memory to a file, so we can confirm that how the variable is saves in memory. – Jake Nov 15 '17 at 12:38
  • in C# you can use this to save class to file. https://stackoverflow.com/questions/17338571/writing-bytes-from-a-struct-into-a-file-with-c-sharp – Jake Nov 15 '17 at 12:46
  • @Jake: It seems that your assumption is right. The two binary files are having different content as I can see in text editor. Also file sizes are different 178 bytes and 192 bytes. By the way, to keep this discussion shorter can we discuss somewhere outside? If necessary, please drop me a message from contact page on [www.ravijoshi.xyz](http://www.ravijoshi.xyz) Thanks again for the help. – ravi Nov 17 '17 at 15:14

0 Answers0