C++ Fast way to convert between image formats - c++

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

Related

cimg pixel value - numerical

is there a way to get the int value of a pixel returned with cimg? I'm in the process of building a basic ASCII art program that converts JPG's to character arrays, and I have the entire utility built out but I cann not find a way to get the unsigned char's converted into the range of ints I need (0-255, although the specifics don't matter so long as its a predictable interval).
Does anyone have any idea how to get a numerical pixel value from a JPG? (library suggestions or anything else are completely welcome)
Here is the pixel output:
\�_b��}�HaX�gNzԴ�����p��-�u�����lqu��Lߐ_"T������{�y�sricX[[TXgZ]`a~�t91960d�BpvJ0kY#uR!BpMWb\W?j"#���dCy2+4?ڽ�TT<Tght%P%y;mhͬ�����8#1�H��)����:4lu���CY|��u&<_��ī��������������ȿF�����LP:����N���-�Q�+�2;E3(�SdRO6��NI16j{#�0((
: pixel data
It's already been converted to black and white, so even accessing the numerical value of one color channel off the cimg would be fine. I just can't seem to get any kind of intelligible/manipulable output from the image, even though the image itself is exactly what i'm looking for.
cast it as an int using (int)img(x,y) and ignore the extra channels

Write a RGBA8 image as a R32UI

I have an image with the format R8G8B8A8 (Unorm).
I want to write uint data on it (to be able to use atomic function).
So, when I want to "write" it, I am using in the glsl :
layout(set = 0, binding = 2, r32ui) restrict writeonly uniform uimage3D dst;
However, when I am performing something like
imageStore(dst, coords, uvec4(0xffffffff));
RenderDoc (and my app as well) tells me that all my values are 0 (instead of 1.0 (255 unorm)).
If I replace the r32ui by rgba8 everything works fine but I can not use atomic values. So I wonder if it is possible to do such thing. (However, if I use a r32f instead of rgba8, it works fine as well).
Do you have any solution?
Vulkan specification guarantees that atomic operations must be supported for storage images (VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT) with only R32_UINT and R32_SINT formats. Implementations may add such support for other formats as well but it's not obligatory. So it's nothing strange that atomic operations don't work with rgba8 format.
Next. You can create an image view with a different format than the format of the image. In such case the image view's format must be compatible with the image's format. In case of the R8G8B8A8 format, both SINT and UINT R32 formats are compatible (have the same number of bits). But to be able to create an image view with a different format, image itself must be created with a VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT flag.
One last thing - there is a note in the specification about format compatibility/mutable images:
Values intended to be used with one view format may not be exactly
preserved when written or read through a different format. For
example, an integer value that happens to have the bit pattern of a
floating point denorm or NaN may be flushed or canonicalized when
written or read through a view with a floating point format.
Similarly, a value written through a signed normalized format that has
a bit pattern exactly equal to -2^b may be changed to -2^b + 1 as
described in Conversion from Normalized Fixed-Point to Floating-Point.
Maybe this is the problem? Though it seems that there should be no conversion between rgba8 (unorm) and r32 (uint). Did validation layers report any warnings or errors? What layout is Your image in when You try to store data in it? Don't forget that:
Load and store operations on storage images can only be done on images
in the VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR or VK_IMAGE_LAYOUT_GENERAL
layout.

how to wide gamut ,convert from 8bit to 10bit

I know that the video we watched on the tv is compressed.The range
of the gamut will be narrow.I want to know if there is a magical way
can achieve the extending.Dolby claimd the Perceptual
Quantizer(PQ)EOTE .there is two function Eg.the Perceptual
Quantizer(PQ)EOTE this quetion is like the way to convert bt709 to bt2020.
I want to convert 8bit to 10bit like the x264. the computer suports only the 8 |16|32 bit.so which kinde of data type to save the 10bit .someone said that we use the 16bit ,the last six bit we use zero to fill.is that right ,i dont think thats a good way.many thanks
There's no magical way to extend color data to a wider gamut. You could try to "stretch" data from the existing gamut, and the result would achieve the vividness of the wider gamut, but lose accuracy.
Normally the three 10-bit channels are packed into a 32-bit integer.

Save float * images in 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

RGB color to HSL bytes

I've seen some implementations for converting RGB to HSL. Most are accurate and work in both directions.
To me its not important that it will work in 2 directions (no need to put back to RGB)
But i want code that returns values from 0 to 255 max, also for the Hue channel.
And I wouldnt like to do devisions like Hue/360*250 i am searching for integer based math no Dwords (its for another system), nice would be some kind of boolean logix (and/or/xor)
It should not do any integer or real number based math, the goal is code
working only using byte math.
Maybe someone already has found such math when he used code like
c++ or
c# or
python
Which i would be able to translate to c++
Checkout the colorsys module, it has methods like:
colorsys.rgb_to_hls(r,g,b)
colorsys.hls_to_rgb(h,l,s)
The easyrgb site has many code snippets for color space conversion. Here's the rgb->hsl code.