准备
FreeImage 库,自己编译或下载
这里只提供 macOS 版的静态库 点击这里下载。密码: p2lb。
代码:
现在仅支持读取 CV_8UC3 / CV8UC4 的 gif 图。
#include <opencv2/opencv.hpp>
#include "FreeImage.h"
using namespace cv;
void show_gif2(const char* path, int interval_ms) {
// path: 文件路径
// interval ms:每张图片显示间隔
FreeImage_Initialise();
// 获取文件名,然后作为窗口名(没必要)
char fn[strlen(path)];
const char *ptr = strrchr(path, '/');
sprintf(fn, "%s", ptr+1);
String title(fn);
namedWindow(title);
// load
FIMULTIBITMAP* fimb = FreeImage_OpenMultiBitmap(FIF_GIF, path,
0, 1, 0, GIF_PLAYBACK);
// frame count
int image_count = FreeImage_GetPageCount(fimb);
if (!image_count)
return;
// pre define size
int width = 0, height = 0;
// other buffer variables
int mat_type = 0;
int channels = 0;
RGBQUAD ptrPalette;
Mat mat;
for (int cur_frame = 0; cur_frame < image_count; cur_frame++) {
FIBITMAP* fib_frame = FreeImage_LockPage(fimb, cur_frame);
if (cur_frame == 0) {
uint min_bits = FreeImage_GetBPP(fib_frame);
// 现在只适配单个颜色8位,RGB 或 RGBA 的 mat,因此 3*8 或 4*8 位:
assert(min_bits == 32 || min_bits == 24);
FREE_IMAGE_COLOR_TYPE color_type = FreeImage_GetColorType(fib_frame);
width = FreeImage_GetWidth(fib_frame);
height = FreeImage_GetHeight(fib_frame);
if (color_type == FIC_RGBALPHA) {
mat_type = CV_8UC4;
channels = 4;
} else if (color_type == FIC_RGB) {
mat_type = CV_8UC3;
channels = 3;
} else {
assert(false); // 只适配 RGB 和 RGBA
}
mat = Mat(height, width, mat_type);
}
int base;
for (int i = 0; i < height; i++) {
// FreeImage_GetPixel 从左下角开始,因此需要翻转 y 轴
uchar* ptrImgDataPerLine = mat.data + (height - i - 1)*mat.step;
for(int j = 0; j < width; j++) {
FreeImage_GetPixelColor(fib_frame, j, i, &ptrPalette);
base = channels*j;
ptrImgDataPerLine[base] = ptrPalette.rgbBlue;
ptrImgDataPerLine[base+1] = ptrPalette.rgbGreen;
ptrImgDataPerLine[base+2] = ptrPalette.rgbRed;
if (channels == 4)
ptrImgDataPerLine[base+3] = ptrPalette.rgbReserved;
}
}
imshow(title, mat);
FreeImage_UnlockPage(fimb, fib_frame, 1);
waitKey(interval_ms);
}
FreeImage_DeInitialise();
}
其他
可以稍微修改一下代码,即可实现获得 mat 数组或通过回调操作每一帧。