使用 FreeImage 库读取 gif 彩色图像并将其转换为 OpenCV Mat
Reading gif color image with FreeImage library and convert it to OpenCV Mat
当我将 Freeimage FIBITMAP* 中的 gif 彩色图像从 at 转换为 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
我看到了这两个 post 但他们有同样的问题。
更新:我找到了解决方案。
使用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);
问题是您没有正确处理图像 - 对您来说有问题的图像有两个共同点:
它们是 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
当我将 Freeimage FIBITMAP* 中的 gif 彩色图像从 at 转换为 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());
如果我使用此代码将图像转换为 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);
- 如果我将 CV_8UC3 更改为 CV_8UC1,我会看到 A3.jpg。
对于jpg或tif等其他格式不存在该问题。解决办法是什么?
另一个示例是 B1.gif、第二阶段的分段错误 和 B3.jpg。
我看到了这两个 post 但他们有同样的问题。
更新:我找到了解决方案。
使用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);
问题是您没有正确处理图像 - 对您来说有问题的图像有两个共同点:
它们是 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