第五次实验:JPEG原理分析

JPEG概述

JPEG( Joint Photographic Experts Group)即联合图像专家组,是用于连续色调静态图像压缩的一种标准,文件后缀名为.jpg或.jpeg,是最常用的图像文件格式。其主要是采用预测编码(DPCM),离散余弦变换(DCT)以及熵编码的联合编码方式,以去除冗余的图像和彩色数据,属于有损压缩格式,它能够将图像压缩在很小的储存空间,一定程度上会造成图像数据的损伤。

JPEG编码原理

JPEG编码的主要步骤为:零电平偏置,DCT变换,量化;对于DC系数来说,进行DPCM+Huffman编码;对于AC系数来说,进行之字形扫描+游程编码+Huffman编码。

实验步骤 :

将输出保存为YUV文件

static void write_yuv(const char *filename, int width, int height, unsigned char **components)
{
  FILE *F;
  char temp[1024];
 
  snprintf_s(temp, 1024, "%s.YUV", filename);
  fopen_s(&F,temp, "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);
}

 struct huffman_table:存储Huffman码表

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];
};

struct component:储存当前8×8像块中有关解码的信息

struct component 
{
  unsigned int Hfactor; // 水平采样因子
  unsigned int Vfactor; // 垂直采样因子
  float* Q_table;   // 指向该8×8块使用的量化表
  struct huffman_table *AC_table;   // 指向该块使用的AC Huffman表
  struct huffman_table *DC_table;   // 指向该块使用的DC Huffman表
  short int previous_DC;    // 前一个块的直流DCT系数
  short int DCT[64];    // DCT系数数组
    
#if SANITY_CHECK
  unsigned int cid;
#endif
};

struct jdec_private:JPEG数据流结构体,用于存储JPEG图像宽高、数据流指针、Huffman码表等内容,并包含struct huffman_table和struct component

struct jdec_private
{
  /* Public variables */
  uint8_t *components[COMPONENTS];  /* 分别指向YUV三个分量的三个指针 */
  unsigned int width, height;	/* 图像宽高 */
  unsigned int flags;

  /* Private variables */
  const unsigned char *stream_begin, *stream_end;
  unsigned int stream_length;

  const unsigned char *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];
};

解码流程

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];

  /* 将JPEG读入缓冲区 */
  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");

  /* 解析JPEG文件头 */
  if (tinyjpeg_parse_header(jdec, buf, length_of_file)<0)
    exitmessage(tinyjpeg_get_errorstring(jdec));

  /* 计算图像宽高 */
  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);

  /* 按照指定的输出格式保存输出文件 */
  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(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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值