opencvopencv3.0freeimage

Reading gif color image with FreeImage library and convert it to OpenCV Mat


Colors got lost when I convert a gif color image in Freeimage FIBITMAP* fromat to OpenCV Mat. I use opencv 3.1.0.

  1. 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());
    

A1.gif A1.gif

  1. 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);
    

A2.jpg A2.jpg

  1. If I Change CV_8UC3 to CV_8UC1, I see A3.jpg.

A3.jpg A3.jpg

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 B1.gif(It seems that when I uploaded this photo alpha channel was removed.)

B3.gif B3.gif

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

Solution

  • The problem is that you are not handling the images correctly - the images that are problematic to you have two things in common:

    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