Save float * images in C++

4.9k Views Asked by At

I wanted to understand how I can save an image of type float:

float * image;

Allocated in this way:

int size = width * height;
image = (float *)malloc(size * sizeof(float));

I tried using the CImg library, but does not accept float directly. Infact, i only use it to capture image to float, because I need only float images.

CImg<float> image("image.jpg");
int width = image.width(); 
int height = image.height();
int size = width*height
float * image = image.data();

How do I save this picture to float from .jpg or .bmp readable. I thought to open a write buffer but not save me anything and I can not read from a file!

5

There are 5 best solutions below

4
On

well, what you need is first of all to realize what you are tying to do. you are creating a pointer to float array

image=(float *)malloc(size* sizeof(float));

and then you're doing

float * image =image.data();

which is double use of image that will cause a compiler error and a bad thing to do also if you could.

now you should read on CImg here and see that Data() returns a pointer to the first pixel of the image.

now that we established all of that let's go to the solution: if you want to save the float array to a file use this example

#include <fstream.h>

void saveArray(float* array, int length);

int main()
{
    float image[] = { 15.25, 15.2516, 84.168, 84356};
    saveArray(floatArray, sizeof(image)/ sizeof(image[0]));

    return 0;
}

void saveArray(float* array, int length)
{
    ofstream output("output.txt");

    for(int i=0;i<length;i++)
    {
        output<<array[i]<<endl;
    }
}
4
On

Since the JPEG image format only supports 8 bit color components (actually the standard allows for 12 bit, but I have nver seen an implementation of that), you cannot do this with JPEG.

You may be able to do this with a .bmp file. See my answer to a question with a possible way to do this with the OpenCV library. With some other library it may be easy with .bmp files because OpenCV assumes 8 bit color channels even though, as fas I know, the .bmp format doesn't dictate that.

Do you need compression? If not just write a binary file, or store the file in yml format, etc.

If you need compression OpenEXR would be option to consider. Probably Image Magick would be the best implementation for you as it integrates well with CImg. Since CImg doesn't natively support .jpg, I suspect that you may already have Image Magick.

0
On

Well I can see from your code that you are using only 32bit float grayscale (no R,G,B just I) so this are my suggestions:

  1. Radiance RGBE (.hdr) use 3x8bit mantisa for R,G,B and 1x8bit exponent which gives you only 16bit precision. But if you use also R,G,B than for simulation purposes this format is not siutable for you. (you loose to much precision because of that the exponent is the same for all channels)

  2. any HDR format is not native so you need to install viewers and must code read/write functions for your source code or use of libs

  3. non HDR formats (bmp,jpg,tga,png,pcx...) If you use grayscale only than this is the best solution for you. These formats are usualy 8bit per channel so you can use 24-32bits together for your single intensity. Also you can view/edit these images natively on most OS. there are 2 ways to do this.

    • for 32bit images you can simply copy float to color =((DWORD*)(&col))[0]; where col is your float pixel. This is simplest without precision loss but if you view your image it will be not pretty :) because floats are stored in different way than integer types.

    • use of color palette. Create color scale palette from min to max possible value of your pixel colors (more colors it has more precision is saved). then bound whole image to this values. after this convert float value to index in your palette and store it (for save) and reverse get float from index in palette from color (for load) in this way the picture will be viewable similar to thermal images ... the conversion from float value to index/RGB color can be done linearly (loose lots of precision) or nonlinearly (by exp,log functions or any nonlinear you want) In best case if you use 24bit pixels and have scale palette from all 2^24 colors and you use nonlinear conversion than you loose only 25% of precision (if you really use whole dynamic range of float, if not than the loss is smaller even down to zero)

tips for scale:

  • look at the light spectrum colors its a good color scale for start (there are many simple source codes that create this with some fors just google), you can also use any color gradient patterns.

  • nonlinear function should be changing less on float range where you need to keep precision (range where most of your pixels can be) and changing much where precision is not important (+/- NaN). I usualy use exp,ln or tan, but you must scale them to range of your color scale palette.

0
On

The BMP file format is pretty simple: https://en.m.wikipedia.org/wiki/BMP_file_format

Read the header to determine height, width, bpp, and data start index. And then just start filling in your float array by casting the pixel channel values to float (starting from the index specified in header), going across the width. When you reach module the specified width, go to next row in array.

JPG decoding is more complex. I would advise against rying to do it yourself.

1
On

If you want to save float values, you need to use a format that supports them - which is not JPEG and not BMP. The most likely options are:

  • TIFF - which requires a library to write

  • FITS - which is mainly used for Astronomy data, and is not too hard to write

  • PFM (Portable Float Format) which is a least common denominator format, in the same vein as NetPBM format and which is described here.

The good news is that CImg supports PFM out-of-the-box with no additional libraries required. So the answer to your question is very simple:

#include "CImg.h"
using namespace cimg_library;
int main() {
   CImg<float> image("image.png");
   image.normalize(0.0,1.0);
   image.save_pfm("result.pfm");
}

If you want to view your image later, ImageMagick understands all the above formats and can convert any of them to anything else:

convert result.pfm image.jpg       # convert PFM to JPG
convert result.pfm image.png       # convert PFM to PNG
convert result.tif image.bmp       # convert TIF to BMP

Keywords: CImg, C++, C, float, floating point, image, image processing, save as float, real, save as real, 32-bit, PFM, Portable Float Map