Write int16_t Array to Text File Without Looping

160 views Asked by At

I am trying to write int61_t data to a ply file (a text file with a special header). I a piece of code that does this with a time consuming loop I am trying to speed it up. I want to avoid the time spent iterating through the array by putting my data directly into ofs.write. Can I do this?

This is what I've tried

The functional, but slow, code is as follows:

int width = point_cloud_image.get_width_pixels();
int height = point_cloud_image.get_height_pixels();
int i_max = width * height;
// get data
int16_t* point_cloud_image_data = (int16_t*)(void*)point_cloud_image.get_buffer(); 

std::stringstream ss;
for (int i = 0; i < i_max; i++) // executes 921600 times - this is the bottleneck
{  
    ss << point_cloud_image_data[3 * i + 0\] << " " << point_cloud_image_data[3 * i + 1\] << " " <<  point_cloud_image_data[3 * i + 2] << "\n";  
}

// save to the ply file
std::ofstream ofs("myfile.ply", std::ios::out | std::fstream::binary); // text mode first
ofs << "ply\n" << "format ascii 1.0\n" << "element vertex" << " " << i_max << "\n" << "property float x\n" << "property float y\n" << "property float z\n" << "end_header\n" << std::endl; 
ofs.write(ss.str().c_str(), (std::streamsize)ss.str().length());
ofs.close();

I want to avoid the time spent iterating through the array by putting my point_cloud_image_data pointer directly into ofs.write. My code to do that looks like this:

int width = point_cloud_image.get_width_pixels();
int height = point_cloud_image.get_height_pixels();
int i_max = width * height;
// get data
int16_t* point_cloud_image_data = (int16_t*)(void*)point_cloud_image.get_buffer();

// save to the ply file
std::ofstream ofs("myfile.ply", std::ios::out | std::fstream::binary); // text mode first
ofs << "ply\n" << "format ascii 1.0\n" << "element vertex" << " " << i_max << "\n" << "property float x\n" << "property float y\n" << "property float z\n" << "end_header\n" << std::endl; 
ofs.write((char*)(char16_t*)point_cloud_image_data, i_max);
ofs.close();

This is a lot faster, but now point_cloud_image_data is written in binary (the file contains characters like this: ¥ûú). How can I write the array to the text file without a time consuming loop?

1

There are 1 answers

0
rustyx On

Integers are stored in the computer in binary representation. To write an array of integer values to a text file, each one needs to be converted to a series of decimal digits. So you're going to need a loop. Even with buffering and compiler optimizations enabled, conversion of binary to text and back will inevitably be slower than directly working with binary data.

But if all you care about is raw performance, the PLY format can actually be binary. So your second attempt might actually work and produce a working (albeit non-human-readable) PLY file.

int width = point_cloud_image.get_width_pixels();
int height = point_cloud_image.get_height_pixels();
int i_max = width * height;

std::ofstream ofs("myfile.ply", std::ios::out | std::fstream::binary);
ofs << "ply\n"
    << (is_little_endian
        ? "format binary_little_endian 1.0\n"
        : "format binary_big_endian 1.0\n")
    << "element vertex " << i_max << "\n"
    << "property short x\n"
    << "property short y\n"
    << "property short z\n"
    << "end_header\n";
ofs.write((const char*)point_cloud_image.get_buffer(), i_max * 2 * 3);
ofs.close();

The is_little_endian check is optional and can be omitted, but it makes the code a little bit more portable.

int num = 1;
bool is_little_endian = *(char *)&num == 1;