Save float * images in C++ - c++

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!

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;
}
}

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.

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:
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)
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
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.

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.

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

Related

Save exr/pfm to bitmap CImg

I am trying to convert some bitmap files into custom images (exr, pfm, whatever), and after that, back to bitmap:
CImg<float> image(_T("D:\\Temp\\test.bmp"));
image.normalize(0.0, 1.0);
image.save_exr(_T("D:\\Temp\\test.exr"));
and goes fine (same for .pfm file), I mean the exr file is ok, same for pfm file.
But when this exr, or pfm file I trying to convert back to bitmap:
CImg<float> image;
image.load_exr(_T("D:\\Temp\\test.exr")); // image.load_pfm(_T("D:\\Tempx\\test.pfm"));
image.save_bmp(_T("D:\\Temp\\test2.bmp"));
the result, test2.bmp is black. Complete. Why ? What I am doing wrong ?
Some image formats support saving as float, but most formats save as unsigned 8 bit integer (or uint8), meaning normal image values are from 0 to 255. If you try to save an array that is made up of floats from 0 to 1 into a format that does not support floats, your values will most likely be converted to integers. When you display your image with most image-viewing software, it'll appear entirely black since 0 is black and 1 is almost black.
Most likely when you save your image to bitmap it is trying to convert the values to uint8 but not scaling properly. You can fix this by multiplying normalized values between 0 and 1 by 255. img = int(img*255) or using numpy img = (img*255).astype(np.uint8).
It is also possible that somehow your save function is able to preserve floating point values in the bitmap format. However your image viewing software might not know how to view/display a float image. Perhaps use some imshow function (matplotlib.pyplot can easily display floating point grayscale arrays) between each line of code to check if the arrays are consistent with what you expect them to be.

Armadillo porting imagesc to save image bitmap from matrix

I have this matlab code to display image object after do super spectrogram (stft, couple plca...)
t = z2 *stft_options.hop/stft_options.sr;
f = stft_options.sr*[0:size(spec_t,1)-1]/stft_options.N/1000;
max_val = max(max(db(abs(spec_t))));
imagesc(t, f, db(abs(spec_t)),[max_val-60 max_val]);
And get this result:
I was porting to C++ successfully by using Armadillo lib and get the mat results:
mat f,t,spec_t;
The problem is that I don't have any idea for converting bitmap like imagesc in matlab.
I searched and found this answer, but seems it doesn't work in my case because:
I use a double matrix instead of integer matrix, which can't be mark as bitmap color
The imagesc method take 4 parameters, which has the bounds with vectors x and y
The imagesc method also support scale ( I actually don't know how it work)
Does anyone have any suggestion?
Update: Here is the result of save method in Armadillo. It doesn't look like spectrogram image above. Do I miss something?
spec_t.save("spec_t.png", pgm_binary);
Update 2: save spectrogram with db and abs
mat spec_t_mag = db(abs(spec_t)); // where db method: m = 10 * log10(m);
mag_spec_t.save("mag_spec_t.png", pgm_binary);
And the result:
Armadillo is a linear algebra package, AFAIK it does not provide graphics routines. If you use something like opencv for those then it is really simple.
See this link about opencv's imshow(), and this link on how to use it in a program.
Note that opencv (like most other libraries) uses row-major indexing (x,y) and Armadillo uses column-major (row,column) indexing, as explained here.
For scaling, it's safest to convert to unsigned char yourself. In Armadillo that would be something like:
arma::Mat<unsigned char> mat2=255*(mat-mat.min())/(mat.max()-mat.min());
The t and f variables are for setting the axes, they are not part of the bitmap.
For just writing an image you can use Armadillo. Here is a description on how to write portable grey map (PGM) and portable pixel map (PPM) images. PGM export is only possible for 2D matrices, PPM export only for 3D matrices, where the 3rd dimension (size 3) are the channels for red, green and blue.
The reason your matlab figure looks prettier is because it has a colour map: a mapping of every value 0..255 to a vector [R, G, B] specifying the relative intensity of red, green and blue. A photo has an RGB value at every point:
colormap(gray);
x=imread('onion.png');
imagesc(x);
size(x)
That's the 3rd dimension of the image.
Your matrix is a 2d image, so the most natural way to show it is as grey levels (as happened for your spectrum).
x=mean(x,3);
imagesc(x);
This means that the R, G and B intensities jointly increase with the values in mat. You can put a colour map of different R,G,B combinations in a variable and use that instead, i.e. y=colormap('hot');colormap(y);. The variable y shows the R,G,B combinations for the (rescaled) image values.
It's also possible to make your own colour map (in matlab you can specify 64 R, G, and B combinations with values between 0 and 1):
z[63:-1:0; 1:2:63 63:-2:0; 0:63]'/63
colormap(z);
Now for increasing image values, red intensities decrease (starting from the maximum level), green intensities quickly increase then decrease, and blue values increase from minuimum to maximum.
Because PPM appears (I don't know the format) not to support colour maps, you need to specify the R,G,B values in a 3D array. For a colour order similar to z you would neet to make a Cube<unsigned char> c(ysize, xsize, 3) and then for every pixel y, x in mat2, do:
c(y,x,0) = 255-mat2(y,x);
c(y,x,1) = 255-abs(255-2*mat2(y,x));
x(y,x,2) = mat2(y,x)
or something very similar.
You may use SigPack, a signal processing library on top of Armadillo. It has spectrogram support and you may save the plot to a lot of different formats (png, ps, eps, tex, pdf, svg, emf, gif). SigPack uses Gnuplot for the plotting.

How to convert CImg float image type to unchar image(0-255) type

I am using CImg library and implementing non maximum suppression for Harris Corner Detector. Because calculation of numbers like determinants requires float type image, I declared images as float type. But when exracting local maximum on the harris response float image, I found it hard to set the threshold because I don't know what exactly the values of the pixels on a float image are, and I got some very strange points extracted which actually weren't the ones I wanted. For example I printed out the values of the points, then I found pixel values like 6e+9 or 1.8e+5, and I don't know what they mean. Is there a way to convert a float image into unchar image so that I can set an integer threshold for local maximum extraction? Thanks in advance!
You just have to normalize your image values, like this :
CImg<unsigned char> img_normalized = img.get_normalize(0,255);
then work on the values of 'img_normalized' instead.

How to convert bitmaps to 'matrices' that can be processed in C++ ( ANN )?

I want to feed my extracted character bitmaps (.bmp files) into some kind of matrices that can be processed in C++ and then fed into the artificial neural network e.g. the network will take 72 inputs - each one as a pixel of the binarized picture of dimensions 6 x 12.
For instance: I have a binarized bitmap of size let's say 40 x 80. I want to make out of it a structure that will have dimensions 6 x 12 and it would consist of my scaled bitmap. So I need a bitmap library that would allow me to scale the bmps and then fed them into the ANN. (As some of you stated already, they will be stored already as a matrix of so kind so no transformations will be necessary)
What can I use in here ?
It seems that any image processing library could suit your needs. So, my advice would be to use a library that is as simple as possible to integrate in your build process.
In this context, the CImg library is extremely easy to us, as it is composed of a simple .h file.
Concerning your need, a possible implementation would be
#include "CImg.h"
using namespace cimg_library;
int main(int argc,char **argv)
{
CImg<unsigned char> image("img/logo.bmp");
//Simple resize with nearest neighbour interpolation
//image = image.resize(64, 64);
//If you want to specify the interpolation type
image = image.resize(64, 64, -100, -100, 4);//The last param specifies the interpolation type
//\param interpolation_type Method of interpolation :
// -1 = no interpolation : raw memory resizing.
// - 0 = no interpolation : additional space is filled according to \p border_condition.
// - 1 = nearest-neighbor interpolation.
// - 2 = moving average interpolation.
// - 3 = linear interpolation.
// - 4 = grid interpolation.
// - 5 = bicubic interpolation.
// - 6 = lanczos interpolation.
CImgDisplay main_disp(image,"Image resized");
//This last part of code is not usfeul for you, it is only used to display the resized image
while (!main_disp.is_closed() )
main_disp.wait();
return 0;
}
The bitmap file format (see the specs) already store bitmaps as a matrix, or more precisely an array of pixels, which can be divided into 2D array by row (or column, but doesn't matter).
Thus you just have to read the header and get the image size, then read the data in arrays of packed struct (with no padding, as explained here).
This way you will get your matrix, then you can wrap it in a class to store width and height attributes, or even give arrays to constructor of personal-flavor matrices.
Use some sort of bmp lib to access the data (platform dependent). This will usually give you the bmp as a flat array. Take that flat array and plug each value into your matrix structure, or pass it directly into your NN code. Can't offer you much more than this without more info.

C++ Fast way to convert between image formats

Ive got some in memory images in various simple formats, which I need to quickly convert to another format. In cases where the target format contains an alpha channel but the source does not, alpha should be taken as its full value (eg 0xFF for an 8bit target alpha channel).
I need to be able to deal with various formats, such as A8R8G8B8, R8G8B8A8, A1R4G4B4, R5G6B5, etc.
Conversion of pixels between any of these formats is simple, however I don't want to have to manually code every single combination, I also don't want to have a 2 pass solution of converting to a common format (eg A8R8G8B8) before converting again to the final format both for performance reasons, and that if I want to use a higher definition format, say A16B16G16R16 or a floating point I'd either loose some data converting to the intermediate format, or have to rewrite everything to use a different higher definition format...
Ideally id like some sort of enum with values for each format, and then a single method to convert, eg say
enum ImageFormat
{
FMT_A8R8G8B8,//32bit
FMT_A1R4G4B4,//16bit
FMT_R5G6B5,//16bit
FMT_A32R32G32B32F,//128bit floating point format
...
};
struct Image
{
ImageFormat Format;
size_t Width, Height;
size_t Pitch;
void *Data;
};
Image *ConvertImage(ImageFormat *targetFormat, const Image *sourceImage);
You might want boost::gil.
Take a look at FreeImage; it's a library that will convert between various images.
You can also try ImageMagick to just convert back and forth, if you don't want to do anything to them.
10 years ago I used the hermes pixel conversion library, which was very fast. It was possible to convert 640x480 32bit images to 15 or 16 bit images with at least 30 pics per second. We used this for a demo engine. Unfortunately I cannot find a link at the moment. On debian the package is orphaned..
But this is exactly what you want to use for real time usage..