使用FreeImage库读取gif彩色图像并将其转换为OpenCV Mat

时间:2017-02-07 08:10:42

标签: opencv opencv3.0 freeimage

当我将Freeimage FIBITMAP * fromat中的gif彩色图像转换为OpenCV Mat时颜色丢失了。我使用opencv 3.1.0。

  1. 我用以下代码阅读A1.gif:

    FREE_IMAGE_FORMAT format = FreeImage_GetFileType(imgPath.c_str(), 0);
    FIBITMAP *image = FreeImage_Load(format, imgPath.c_str());
    
  2. A1.gif A1.gif

    1. 如果我使用此代码将图像转换为OpenCV Mat并显示它,我会看到A2.jpg。 为什么OpenCV会显示此图片而不是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);
      
    2. A2.jpg A2.jpg

      1. 如果我将 CV_8UC3 更改为 CV_8UC1 ,我会看到A3.jpg。
      2. A3.jpg A3.jpg

        对于jpg或tif等其他格式,问题不存在。解决方案是什么?

        另一个例子是B1.gif,第二阶段的分段错误和B3.jpg。

        B1.gif B1.gif(似乎当我上传这张照片时,alpha通道被删除了。)

        B3.gif B3.gif

        我看到这两个帖子,但他们有同样的问题。

        Convert FreeImage FIBITMAP format to OpenCV Mat

        c++ - FreeImage+OpenCV - 16bit image get distorted

        更新:我找到了解决方案。

        使用FreeImage加载gif并将其转换为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);
        

1 个答案:

答案 0 :(得分:3)

问题是你没有正确处理图像 - 对你有问题的图像有两个共同点:

  • 他们 palettised

  • 他们有一个 alpha 图层

由于它们是palettised,位图中的数字不代表颜色,它们代表调色板中的索引。我不使用或知道 FreeImage ,但您需要获取调色板然后遍历位图,而不是从位图中获取值并将它们放入Mat ,您需要使用位图中的值作为调色板的索引,并在指定的偏移处获取颜色并将其放入Mat。可能有一种ConvertToType()类型的功能可以帮助您 - 在这种情况下,您需要将调色板类型转换为真彩色类型。

其次,你需要处理透明度。如果您的图片具有透明度,则需要 OpenCV 中的4通道Mat,其中包含B,G,R和Alpha /透明度。

相比之下,JPEG图像不包含调色板,不能包含透明度 - 因此它们可以在您的代码中使用: - )

如果您使用的是Linux,那么您将安装 ImageMagick ,并且您可以轻松地为macOS和Windows获取它 - 它是免费的。然后,您可以查看图像,看看我的意思:

identify -verbose drummer.gif | more

<强>输出

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

作为临时修复,您可以尝试将鼓手转换为不支持透明度但 FreeImage 可以读取的PPM

convert drummer.gif drummer.ppm

或者

convert drummer.gif drummer.jpg