运用freeimage实现opencv下的gif解析

来源:互联网 发布:淘宝客店铺推广 编辑:程序博客网 时间:2024/05/27 20:04

在介绍如何解析gif图像文件之前,首先简单介绍一下gif图像文件。

GIF: 任何商业目的运用都需要CompuServe公司授权

  1. 特点:
  • GIF只支持256色以内的图像。
  • GIF采用无损压缩存储,在不影响图像质量的情况下,可以生成很小的文件。(而且,编码解码速度都高于jpeg图像文件)
  • GIF支持透明色,可以让图像浮现在背景上。
  • GIF可以制作成动画,只是它最突出的特点
  1. 文件主要包含的内容:
  • 文件头:用于标识版本号等
  • GIF数据流:包含颜色列表和图像数据等
  • 文件终结器:用于标示文件的终结
  1. 注: 图像数据包含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;
}