在介绍如何解析gif图像文件之前,首先简单介绍一下gif图像文件。
GIF: 任何商业目的运用都需要CompuServe公司授权
- 特点:
- GIF只支持256色以内的图像。
- GIF采用无损压缩存储,在不影响图像质量的情况下,可以生成很小的文件。(而且,编码解码速度都高于jpeg图像文件)
- GIF支持透明色,可以让图像浮现在背景上。
- GIF可以制作成动画,只是它最突出的特点
- 文件主要包含的内容:
- 文件头:用于标识版本号等
- GIF数据流:包含颜色列表和图像数据等
- 文件终结器:用于标示文件的终结
- 注: 图像数据包含LZW编码长度和数据块,数据块的第一个字节标示数据块的大小(数据块大小不一[0, 255])
使用opencv进行解码的同学会发现,由于版权等原因,opencv没有提供解码gif文件的代码。
我简单实现了一个先用freeimage对图像进行解码,再转化为opencv下的IplImage格式。gif文件包含多帧图像,所以用vector保存
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
#include "FreeImage.h" int Gif2IplImage( const char * data, const size_t dataSize, std::vector< cv::Ptr<IplImage> >& mutilImgs) { if (data == NULL && dataSize == 0) return -1; FreeImage_Initialise(); // 初始化freeimage,一定要FreeImage_DeInitialise() FIMEMORY * memory = FreeImage_OpenMemory(( BYTE *)data, dataSize ); if (NULL == memory) { FreeImage_DeInitialise(); return -1; } FREE_IMAGE_FORMAT fif = FreeImage_GetFileTypeFromMemory(memory); if (FIF_UNKNOWN == fif) { fprintf (stderr, "Error in Gif2IplImage: is unknow image type/n" ); if (NULL != memory) FreeImage_CloseMemory(memory); FreeImage_DeInitialise(); return -1; } else if (FIF_GIF != fif) // 不是gif文件不处理 { if (NULL != memory) FreeImage_CloseMemory(memory); FreeImage_DeInitialise(); return 0; } FIMULTIBITMAP* fiBmps = FreeImage_LoadMultiBitmapFromMemory(fif, memory, GIF_DEFAULT); // gif文件解码 if (NULL == fiBmps) { if (NULL != memory) FreeImage_CloseMemory(memory); FreeImage_DeInitialise(); return -1; } int num = FreeImage_GetPageCount(fiBmps); // 获取多帧 for ( int i = 0; i <= num; i ++) { FIBITMAP* fiBmp = FreeImage_LockPage(fiBmps, i); if (fiBmp) { Ptr<IplImage> pImg = FIBITMAP_2_IplImage(fiBmp, fif); // 将解码的图像数据封装成opencv下的IplImage格式 FreeImage_UnlockPage(fiBmps, fiBmp, false ); if (NULL == pImg) { if (NULL != memory) FreeImage_CloseMemory(memory); if (NULL != fiBmps) FreeImage_CloseMultiBitmap(fiBmps, GIF_DEFAULT); FreeImage_DeInitialise(); return -1; } mutilImgs.push_back(pImg); } } if (NULL != memory) FreeImage_CloseMemory(memory); if (NULL != fiBmps) FreeImage_CloseMultiBitmap(fiBmps, GIF_DEFAULT); FreeImage_DeInitialise(); return 0; } cv::Ptr<IplImage> FIBITMAP_2_IplImage( FIBITMAP* fiBmp, const FREE_IMAGE_FORMAT& fif) // 将解码的图像数据封装成opencv下的IplImage格式 { if (NULL == fiBmp || FIF_GIF != fif) return NULL; int width = FreeImage_GetWidth(fiBmp); int height = FreeImage_GetHeight(fiBmp); if (width <= 0 || height <= 0) return NULL; RGBQUAD* ptrPalette = FreeImage_GetPalette(fiBmp); BYTE intens; BYTE * pIntensity = &intens; cv::Ptr<IplImage> pImg = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 3); pImg->origin = 1; for ( int i = 0; i < height; i++) { char * ptrDataLine = pImg->imageData + i * pImg->widthStep; for ( int j = 0; j < width; j ++) { FreeImage_GetPixelIndex(fiBmp, j , i, pIntensity); ptrDataLine[3*j] = ptrPalette[intens].rgbBlue; ptrDataLine[3*j+1] = ptrPalette[intens].rgbGreen; ptrDataLine[3*j+2] = ptrPalette[intens].rgbRed; } } return pImg; } |