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

Posted

技术标签:

【中文标题】使用 FreeImage 库读取 gif 彩色图像并将其转换为 OpenCV Mat【英文标题】:Reading gif color image with FreeImage library and convert it to OpenCV Mat 【发布时间】:2017-02-07 08:10:41 【问题描述】:

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

    我用这段代码阅读了 A1.gif:

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

A1.gif

    如果我使用此代码将图像转换为 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);
    

A2.jpg

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

A3.jpg

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

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

B1.gif(好像我上传这张照片的时候alpha通道被去掉了。)

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

【问题讨论】:

@MarkSetchell 是的。你的答案是正确的,但我一开始无法用 FreeImage 实现它,现在我设法做到了。 【参考方案1】:

问题在于您没有正确处理图像 - 对您有问题的图像有两个共同点:

他们是palettised,而且,

他们有一个alpha

由于它们是调色板,位图中的数字不代表颜色,它们代表调色板中的索引。我不使用也不知道 FreeImage,但您需要获取调色板,然后遍历位图,而不是从位图中获取值并将它们放入 Mat,您需要使用位图中的值作为调色板的索引,并在指定的偏移处获取颜色并将其放入Mat。可能有一个ConvertToType() 之类的函数会为您执行此操作 - 在这种情况下,您需要将 palette 类型转换为 true-colour 类型。

其次,您需要处理透明度。如果您的图像具有透明度,则需要 OpenCV 中的 4 通道 Mat,它具有 B、G、R 和 Alpha/Transparency。

相比之下,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

【讨论】:

啊.. ImageMagick.. 解决方案,好吧,一切;) @Miki Nah,曾经有一个答案是我必须使用 Perl。还有一个 GNU Parallel ;-) @Miki你知道合适的freeimage转换功能吗? @Iman 不,我前段时间写过一个(您已经看到它,因为它已在您的问题中链接)......它不应该适用于所有边缘情况。但是,您可以在此基础上创建自己的函数,添加缺少的代码来处理这种情况。 @MarkSetchell 谢谢。我会检查你的解决方案。

以上是关于使用 FreeImage 库读取 gif 彩色图像并将其转换为 OpenCV Mat的主要内容,如果未能解决你的问题,请参考以下文章

freeimage是啥

FreeImage 2011是干啥的软件

cv lesson1

python plt.imshow 怎么用

python图像数据读取利器-imageio库的使用

matlab怎么使用?