实验五-jpg解码

来源:互联网 发布:锋利的jquery源码 编辑:程序博客网 时间:2024/05/17 22:53

一、实验原理
1.jpg编码
JPEG(Joint Photographic Experts Group),文件后缀名为.jpg,.jpeg,是一种常用的图像文件格式。采用有损压缩方式去除冗余的图像和彩色数据,在获得极高压缩率的同时能展现十分丰富生动的图像。
编码过程如图示:
这里写图片描述
解码为编码的逆过程。
2.jpg文件格式
jpeg文件以Segment的形式组织,均以0xFF开始,后面跟1字节的Marker和2字节的Segment Length(包含Length本身长度,不包括Marker和0xFF)。
常用的Marker有:
1)SOI(start of image)0xFFDB
所有的jpeg文件必须以SOI开始。
2)APPn(reserved for application use)0xFFE0-0xFFEF
eg:FFE0 运用程序保留标记0
FF E0 00 10 4A 46 49 46 00 01 01 01 00 48 00 48 00 00
length 2byte:0X0010=16
标识符:4A 46 49 46 00 –JFIF
Version 2byte:0101
Units 1byte:01 –X,Y are dots per inch
Xdensity 2byte:0x0048 –水平方向点密度
Ydensity 2byte:0x0048 –垂直方向点密度
缩略图水平像素数目 1byte :0x00
缩略图垂直像素数目 1byte :0x00
缩略图24bitRGB 数据:没有缩略图
3)DQT(Define Quantization Table) 0xFFDB
这里写图片描述
length 2byte:0x 00 43
QT信息 1byte 0-3位:QT号(0-3,可能有4张量化表,亮度,色度,可能会有rgb各一张量化表) 4-7位:QT精度(0:8bit,1:16bit)
QT实际数据:nbyte n=64*QT精度的字节数。(对于8*8的宏块来说,共有8*8=64个量化系数)
需要注意的是,jpeg文件中的量化表是按之字形扫描的格式存的,要得到真正的量化表还需要反之字形扫描;

static const unsigned char zigzag[64] = {   0,  1,  5,  6, 14, 15, 27, 28,   2,  4,  7, 13, 16, 26, 29, 42,   3,  8, 12, 17, 25, 30, 41, 43,   9, 11, 18, 24, 31, 40, 44, 53,  10, 19, 23, 32, 39, 45, 52, 54,  20, 22, 33, 38, 46, 51, 55, 60,  21, 34, 37, 47, 50, 56, 59, 61,  35, 36, 48, 49, 57, 58, 62, 63};static void build_quantization_table(float *qtable, const unsigned char *ref_table){  /* Taken from libjpeg. Copyright Independent JPEG Group's LLM idct.   * For float AA&N IDCT method, divisors are equal to quantization   * coefficients scaled by scalefactor[row]*scalefactor[col], where   *   scalefactor[0] = 1   *   scalefactor[k] = cos(k*PI/16) * sqrt(2)    for k=1..7   * We apply a further scale factor of 8.   * What's actually stored is 1/divisor so that the inner loop can   * use a multiplication rather than a division.   */  int i, j;  static const double aanscalefactor[8] = {     1.0, 1.387039845, 1.306562965, 1.175875602,     1.0, 0.785694958, 0.541196100, 0.275899379  };  const unsigned char *zz = zigzag;  for (i=0; i<8; i++) {     for (j=0; j<8; j++) {       *qtable++ = ref_table[*zz++] * aanscalefactor[i] * aanscalefactor[j];     }   }}

解析到的量化表为
这里写图片描述
这里写图片描述
4)SOF(start of Frame)0xFFC0
eg:FF C0 00 11 08 0F C0 0B D0 03 01 22 00 02 11 01 03 11 01
length 2byte :0x11—17byte
图像精度(每个数据样本的位数)1byte:0x08
图像高度 2byte:0x0FC0=4032
图像宽度 2byte : 0X0BD0=3024
颜色分量数 1byte:03(ycrcb)
颜色分量id 1byte:01—-y
采样率 1byte :4-7位水平采样率:2 0-3位垂直采样率:2
量化表号 1byte:00
颜色分量id 1byte:02—-U
采样率 1byte :位水平采样率:1 垂直采样率:1
量化表号 1byte:01
颜色分量id 1byte:03—–V
采样率 1byte :水平采样率:1 垂直采样率:1
量化表号 1byte:01
5)DHT,define Huffman Table 0xFFC4
这里写图片描述
这里写图片描述
length 2byte:0x001f—31byte
huffman表信息 1byte:4-7位huffman表类型(0:Dc,1:Ac):0
0-3位huffman表id:0
huffmanTableIndex:16byte 1-16位码长的码字各有多少个
huffman权值信息:nbyte(n为huffmanTableIndex的和,表示每个码字的权值)
这里写图片描述
6)SOS(start of Scan)0xFFDA
eg:FF DA 00 0C 03 01 00 02 11 03 11 03 3F 00
length 2byte:0x000c—12
颜色分量数 1byte:0x03 –和SOF中的颜色分量数相同
颜色分量信息 6byte:每个颜色分量占2byte
颜色分量id 1byte:0x01
颜色分量使用的huffman编号:0-3位直流分量使用的表号;4-7位交流分量使用的表号
y: 01 dc–0 ac–0
cb:02 dc–1 ac–1
cr: 03 dc–1 ac–1
压缩图像数据 3byte:
谱选择开始 1byte 固定值0x00
谱选择结束 1byte 固定值0x3f
谱选择 1byte 在基本jpeg中总为00
7)EOI end of image 0xFFD9
结束符,jpeg文件中固定为EOI。
3.解码数据结构

struct component {  unsigned int Hfactor; //水平采样因子  unsigned int Vfactor;  float *Q_table;       /* Pointer to the quantisation table to use */  struct huffman_table *AC_table;  struct huffman_table *DC_table;  short int previous_DC;    /* Previous DC coefficient */  short int DCT[64];        /* DCT coef */#if SANITY_CHECK  unsigned int cid;#endif};
struct jdec_private{  /* Public variables */  uint8_t *components[COMPONENTS];  unsigned int width, height;   /* Size of the image */  unsigned int flags;  /* Private variables */  const unsigned char *stream_begin, *stream_end;  unsigned int stream_length;  const unsigned char *stream;  /* Pointer to the current stream */  unsigned int reservoir, nbits_in_reservoir;  struct component component_infos[COMPONENTS];  float Q_tables[COMPONENTS][64];       /* quantization tables */  struct huffman_table HTDC[HUFFMAN_TABLES];    /* DC huffman tables   */  struct huffman_table HTAC[HUFFMAN_TABLES];    /* AC huffman tables   */  int default_huffman_table_initialized;  int restart_interval;  int restarts_to_go;               /* MCUs left in this restart interval */  int last_rst_marker_seen;         /* Rst marker is incremented each time */  /* Temp space used after the IDCT to store each components */  uint8_t Y[64*4], Cr[64], Cb[64];  jmp_buf jump_state;  /* Internal Pointer use for colorspace conversion, do not modify it !!! */  uint8_t *plane[COMPONENTS];  //add by zhn  int tempY[4];  int tempU,tempV;  //end add};
struct huffman_table{  /* Fast look up table, using HUFFMAN_HASH_NBITS bits we can have directly the symbol,   * if the symbol is <0, then we need to look into the tree table */  short int lookup[HUFFMAN_HASH_SIZE];  /* code size: give the number of bits of a symbol is encoded */  unsigned char code_size[HUFFMAN_HASH_SIZE];  /* some place to store value that is not encoded in the lookup table    * FIXME: Calculate if 256 value is enough to store all values   */  uint16_t slowtable[16-HUFFMAN_HASH_NBITS][256];};

4.typedef指向函数的用法
typedef void (*decode_MCU_fct) (struct jdec_private *priv);
decode_MCU_fct decode_MCU;
decode_MCU=decode_MCU_2x2_1plane;
decode_MCU(priv);
decode_MCU_fct是一个函数指针,用它来声明的decode_MCU也是一个函数指针,并用它指向decode_MCU_2x2_1plane函数,传入参数即可调用。
二、实验步骤
1)读取文件;
2)解析Segment Marker;
3)根据每个分量的水平和垂直采样因子计算MCU的大小,得到每个MCU中宏块的个数;
4)对每个MCU解码,知道解析到EOI,解码结束;
5)将y,cb,cr转化为需要的彩色空间并保存。
三、关键代码分析

int convert_one_image(const char *infilename, const char *outfilename, int output_format){  FILE *fp;  unsigned int length_of_file;  unsigned int width, height;  unsigned char *buf;  struct jdec_private *jdec;  unsigned char *components[3];  //add by zhn  unsigned char *yBuffer;  unsigned char *uBuffer;  unsigned char *vBuffer;  //end add  /* Load the Jpeg into memory */  fp = fopen(infilename, "rb");  if (fp == NULL)    exitmessage("Cannot open filename\n");  length_of_file = filesize(fp);  buf = (unsigned char *)malloc(length_of_file + 4);  if (buf == NULL)    exitmessage("Not enough memory for loading file\n");  fread(buf, length_of_file, 1, fp);  fclose(fp);  /* Decompress it */  jdec = tinyjpeg_init();  if (jdec == NULL)    exitmessage("Not enough memory to alloc the structure need for decompressing\n");  if (tinyjpeg_parse_header(jdec, buf, length_of_file)<0)    exitmessage(tinyjpeg_get_errorstring(jdec));  /* Get the size of the image */  tinyjpeg_get_size(jdec, &width, &height);  snprintf(error_string, sizeof(error_string),"Decoding JPEG image...\n");  if (tinyjpeg_decode(jdec, output_format) < 0)    exitmessage(tinyjpeg_get_errorstring(jdec));  /*    * Get address for each plane (not only max 3 planes is supported), and   * depending of the output mode, only some components will be filled    * RGB: 1 plane, YUV420P: 3 planes, GREY: 1 plane   */  tinyjpeg_get_components(jdec, components);  /* Save it */  switch (output_format)   {    case TINYJPEG_FMT_RGB24:    case TINYJPEG_FMT_BGR24:      write_tga(outfilename, output_format, width, height, components);      break;    case TINYJPEG_FMT_YUV420P:      write_yuv_onefile(outfilename, width, height, components);      break;    case TINYJPEG_FMT_GREY:      write_pgm(outfilename, width, height, components);      break;   }  /* Only called this if the buffers were allocated by tinyjpeg_decode() */  tinyjpeg_free(jdec);  /* else called just free(jdec); */  free(buf);  return 0;}
int tinyjpeg_decode(struct jdec_private *priv, int pixfmt)//add by zhn outdctY{  unsigned int x, y, xstride_by_mcu, ystride_by_mcu;  unsigned int bytes_per_blocklines[3], bytes_per_mcu[3];  decode_MCU_fct decode_MCU;  const decode_MCU_fct *decode_mcu_table;  const convert_colorspace_fct *colorspace_array_conv;  convert_colorspace_fct convert_to_pixfmt;  //add by zhn  unsigned char *yBuffer;  unsigned char *uBuffer;  unsigned char *vBuffer;  int *yB,*uB,*vB;  int *ytemp,*utemp,*vtemp;  int dcSize,i,j;  FILE *O,*D;  int debug=1;  int count[256],countBefore[256];  int Q_table[3][64];  int MaxY,MaxU,MaxV;  memset(count,0,256*sizeof(int));  memset(countBefore,0,256*sizeof(int));  //end add  if (setjmp(priv->jump_state))    return -1;  /* To keep gcc happy initialize some array */  bytes_per_mcu[1] = 0;  bytes_per_mcu[2] = 0;  bytes_per_blocklines[1] = 0;  bytes_per_blocklines[2] = 0;  decode_mcu_table = decode_mcu_3comp_table;  switch (pixfmt) {     case TINYJPEG_FMT_YUV420P:       colorspace_array_conv = convert_colorspace_yuv420p;       if (priv->components[0] == NULL)     priv->components[0] = (uint8_t *)malloc(priv->width * priv->height);       if (priv->components[1] == NULL)     priv->components[1] = (uint8_t *)malloc(priv->width * priv->height/4);       if (priv->components[2] == NULL)     priv->components[2] = (uint8_t *)malloc(priv->width * priv->height/4);       bytes_per_blocklines[0] = priv->width;       bytes_per_blocklines[1] = priv->width/4;       bytes_per_blocklines[2] = priv->width/4;       bytes_per_mcu[0] = 8;       bytes_per_mcu[1] = 4;       bytes_per_mcu[2] = 4;       break;     case TINYJPEG_FMT_RGB24:       colorspace_array_conv = convert_colorspace_rgb24;       if (priv->components[0] == NULL)     priv->components[0] = (uint8_t *)malloc(priv->width * priv->height * 3);       bytes_per_blocklines[0] = priv->width * 3;       bytes_per_mcu[0] = 3*8;       break;     case TINYJPEG_FMT_BGR24:       colorspace_array_conv = convert_colorspace_bgr24;       if (priv->components[0] == NULL)     priv->components[0] = (uint8_t *)malloc(priv->width * priv->height * 3);       bytes_per_blocklines[0] = priv->width * 3;       bytes_per_mcu[0] = 3*8;       break;     case TINYJPEG_FMT_GREY:       decode_mcu_table = decode_mcu_1comp_table;       colorspace_array_conv = convert_colorspace_grey;       if (priv->components[0] == NULL)     priv->components[0] = (uint8_t *)malloc(priv->width * priv->height);       bytes_per_blocklines[0] = priv->width;       bytes_per_mcu[0] = 8;       break;     default:#if TRACE         fprintf(p_trace,"Bad pixel format\n");         fflush(p_trace);#endif       return -1;  }

四、实验结果分析

static void write_yuv_onefile(const char *filename, int width, int height, unsigned char **components){  FILE *F;  F = fopen(filename, "wb");  fwrite(components[0], width, height, F);  fwrite(components[1], width*height/4, 1, F);  fwrite(components[2], width*height/4, 1, F);  fclose(F);}
/* * Decode a 2x2 *  .-------. *  | 1 | 2 | *  |---+---| *  | 3 | 4 | *  `-------' */static void decode_MCU_2x2_3planes(struct jdec_private *priv){    int i;  // Y  process_Huffman_data_unit(priv, cY);  IDCT(&priv->component_infos[cY], priv->Y, 16);  //add by zhn  priv->tempY[0]=priv->component_infos[cY].DCT[4];  //end add  process_Huffman_data_unit(priv, cY);  IDCT(&priv->component_infos[cY], priv->Y+8, 16);  //add by zhn  priv->tempY[1]=priv->component_infos[cY].DCT[4];#if debug_dct  for(i=0;i<64;i++)  {      if(priv->component_infos[cY].DCT[i]>=255)          printf("%4d",priv->component_infos[cY].DCT[i]);  }#endif  //end add  process_Huffman_data_unit(priv, cY);  IDCT(&priv->component_infos[cY], priv->Y+64*2, 16);  //add by zhn  priv->tempY[2]=priv->component_infos[cY].DCT[4];  //end add  process_Huffman_data_unit(priv, cY);  IDCT(&priv->component_infos[cY], priv->Y+64*2+8, 16);  //add by zhn  priv->tempY[3]=priv->component_infos[cY].DCT[4];  //end add  // Cb  process_Huffman_data_unit(priv, cCb);  IDCT(&priv->component_infos[cCb], priv->Cb, 8);  //add by zhn#if debug_dct  for(i=0;i<64;i++)  {      if(priv->component_infos[cCb].DCT[i]>=255)          printf("%4d",priv->component_infos[cCb].DCT[i]);  }#endif  priv->tempU=priv->component_infos[cCb].DCT[4];  //end add  // Cr  process_Huffman_data_unit(priv, cCr);  IDCT(&priv->component_infos[cCr], priv->Cr, 8);  //add by zhn#if debug_dct  for(i=0;i<64;i++)  {      if(priv->component_infos[cCr].DCT[i]>=255)          printf("%4d",priv->component_infos[cCr].DCT[i]);  }#endif  priv->tempV=priv->component_infos[cCr].DCT[4];  //end add}

原始图像
这里写图片描述

dc系数图像
这里写图片描述
dc概率分布
这里写图片描述
ac系数1的概率分布
这里写图片描述
ac系数3的概率分布
这里写图片描述
五、实验结论分析
dct的物理意义是将用各频率分量的组合来表示原图像,它的各个系数就表示该频率分量的大小。一张图片的dc系数与原图像的概率分布近似,而ac系数则服从拉普拉斯分布,且频率越高,分布越集中。
附录代码链接
http://download.csdn.net/detail/qq_35473884/9857990

原创粉丝点击