Colors got lost when I convert a gif color image in Freeimage FIBITMAP* fromat to OpenCV Mat. I use opencv 3.1.0.
I read A1.gif with this code:
FREE_IMAGE_FORMAT format = FreeImage_GetFileType(imgPath.c_str(), 0);
FIBITMAP *image = FreeImage_Load(format, imgPath.c_str());
If I convert image to OpenCV Mat with this code and show it, I see A2.jpg. Why OpenCV show this image instead of A1.gif?
Mat img(FreeImage_GetHeight(image), FreeImage_GetWidth(image), CV_8UC3, FreeImage_GetBits(image), FreeImage_GetPitch(image));
namedWindow("Display window", WINDOW_AUTOSIZE);
imshow("Display window", img);
For other formats like jpg or tif the problem dose not exist. what is the solution?
Another example is B1.gif, Segmentation fault for second stage and B3.jpg.
B1.gif(It seems that when I uploaded this photo alpha channel was removed.)
I saw this two post but they have the same problem.
Convert FreeImage FIBITMAP format to OpenCV Mat
c++ - FreeImage+OpenCV - 16bit image get distorted
Update: I found the solution.
The correct code for loading gif with FreeImage and Converting it to OpenCV Mat:
FIBITMAP *image = FreeImage_Load(format, GifImagePath);
RGBQUAD *pal = FreeImage_GetPalette(image);
unsigned width = FreeImage_GetWidth(image);
unsigned height = FreeImage_GetHeight(image);
FIBITMAP *tmp = FreeImage_Allocate(width, height, 24);
BYTE *tmp_bits = FreeImage_GetBits(tmp);
for(int y = 0; y < height; y++) {
for(int x = 0; x < width; x++) {
BYTE t;
//FreeImage_GetPixelIndex(image,x, y, &t);//safer, in animated gif
t = img_bits[x+y*height];//Probably faster
RGBQUAD color = pal[t];
//FreeImage_SetPixelColor(tmp, x, y, &color);//safer, in animated
//Probably faster
tmp_bits[(x+y*height)*3 +FI_RGBA_RED] = color.rgbRed;
tmp_bits[(x+y*height)*3+FI_RGBA_GREEN] = color.rgbGreen;
tmp_bits[(x+y*height)*3+FI_RGBA_BLUE] = color.rgbBlue;
}
}
Mat img(FreeImage_GetHeight(tmp), FreeImage_GetWidth(tmp), CV_8UC3, FreeImage_GetBits(tmp), FreeImage_GetPitch(tmp));
namedWindow("Display window", WINDOW_AUTOSIZE);
imshow("Display window", img);
The problem is that you are not handling the images correctly - the images that are problematic to you have two things in common:
they are palettised, and,
they have an alpha layer
As they are palettised, the numbers in the bitmap do not represent colours, they represent indices into the palette. I don't use, or know, FreeImage, but you need to get the palette and then iterate through the bitmap and instead of taking the values from the bitmap and putting them into the Mat
, you need to use the values in the bitmap as indices into the palette and take the colour at the specified offset and put that into the Mat
. There may be a ConvertToType()
sort of function that will do that for you - in which case you will need to convert from a palette type to a true-colour type.
Secondly, you need to deal with the transparency. If your image has transparency, you will need a 4-channel Mat
in OpenCV, which has B,G,R and Alpha/Transparency.
By comparison, JPEG images do not contain a palette and cannot contain transparency - hence they work in your code :-)
If you are on Linux, you will have ImageMagick installed and you can get it for macOS and Windows easily enough - it's free. You can then look at your images and see what I mean:
identify -verbose drummer.gif | more
Output
Image: drummer.gif
Format: GIF (CompuServe graphics interchange format)
Mime type: image/gif
Class: PseudoClass
Geometry: 800x600+0+0
Units: Undefined
Type: PaletteAlpha <--- Palette and transparency
Endianess: Undefined
Colorspace: sRGB
Depth: 8-bit
Channel depth:
Red: 8-bit
Green: 8-bit
Blue: 8-bit
Alpha: 1-bit <--- 4th transparency layer
As a temporary fix, you could try converting the drummer to PPM
which does not support transparency but which FreeImage can read:
convert drummer.gif drummer.ppm
Or
convert drummer.gif drummer.jpg