【数据压缩(八)】JPEG原理分析及JPEG解码器的调试

JPEG原理分析及JPEG解码器的调试

  • 一、实验目的
  • 二、实验内容
    • 1、JPEG编解码原理
      • (1)零偏置电平下移
      • (2)8x8 DCT
      • (3)量化
      • (4)直流DC系数的DPCM编码
      • (5)AC系数的Z字扫描
      • (6)Huffman编码
        • ①DC系数的Huffman编码
        • ②AC系数的Huffman编码
    • 2、JPEG文件格式
      • (1)Segment的组织形式
      • (2)JPEG的Segment Market
  • 三、实验步骤
    • 0、程序准备
    • 1、运行JPEG解码程序,并输出可供YUVviewer观看的YUV文件
    • 2、程序调试过程的理解
      • (1)理解程序设计的整体框架
      • (2)理解三个结构体的设计目的
        • ①`struct huffman_table`
        • ②`struct component`
        • ③`struct jdec_private`
      • (3)理解在视音频编解码调试中TRACE的目的和含义
    • 3、输出量化矩阵和Huffman码表
      • (1)量化矩阵
      • (2)Huffman码表
      • (3)输出结果
  • 四、实验结论

一、实验目的

  1. 掌握JPEG编解码系统的基本原理。
  2. 初步掌握复杂的数据压缩算法实现,并能根据理论分析需要实现所对应数据的输出。

二、实验内容

1、JPEG编解码原理

【数据压缩(八)】JPEG原理分析及JPEG解码器的调试_第1张图片
JPEG编码过程如上图所示,解码是编码的逆过程。下面以编码为例进行分析。

(1)零偏置电平下移

  • 操作:先对8×8的像块进行零偏置电平下移(Level Offset)。即对于灰度级是2n的像素,通过减去 2n-1,将无符号的整数值变成有符号数。
  • 目的: 使像素的绝对值出现 3 位 10 进制的概率大大减少。
  • 对于n=8,即将0~255的值域,通过减去128转换为值域在-128~127之间的值

(2)8x8 DCT

  • 将原始图像分为8x8的小块, 每个block里有64个像素。
  • 将图像块作为2维离散余弦变换DCT的输入,最后得到DCT变换的输出,如图所示:
    【数据压缩(八)】JPEG原理分析及JPEG解码器的调试_第2张图片

(3)量化

  • 因为人眼对亮度信号比对色差信号更敏感,因此使用了两种量化表:亮度量化值和色差量化值。
  • 根据人眼的视觉特性(对低频敏感,对高频不太敏感)对低频分量采取较细的量化,对高频分量采取较粗的量化。
  • 如果原始图象中细节丰富,则去掉的数据较多,量化后的系数与量化前差别较大。反之,细节少的原始图象在压缩时去掉的数据少些,量化后的系数与量化前差别较小。 【数据压缩(八)】JPEG原理分析及JPEG解码器的调试_第3张图片

(4)直流DC系数的DPCM编码

由于8×8图像块经过DCT变换之后得到的DC直流系数有两个特点:

  • 系数的数值比较大
  • 相邻 8 × 8 图像块的 DC 系数值变化不大:冗余

根据这个特点,JPEG算法使用了差分脉冲调制编码(DPCM)技术,对相邻图像块之间量化DC系数的差值DIFF进行编码:
D I F F k = D C k − D C k − 1 DIFF_k=DC_k-DC_{k-1} DIFFk=DCkDCk1

(5)AC系数的Z字扫描

  • 由于经DCT变换后,系数大多数集中在左上角,即低频分量区,因此采用Z字形按频率的高低顺序读出,可以出现很多连零的机会。可以使用游程编码。尤其在最后,如果都是零,给出EOB (End of Block)即可。
  • 然后,系数序列分组,将非零系数和它前面的相邻的全部零系数分在一组内;每组用两个符号表示 [(Run, Size), (Amplitude)]

Amplitude:表示非零系数的幅度值;
Run:表示零的游程即零的个数;
Size:表示非零系数的幅度值的编码位数。

【数据压缩(八)】JPEG原理分析及JPEG解码器的调试_第4张图片

(6)Huffman编码

①DC系数的Huffman编码

  • 对DIFF用Huffman编码:分成类别,类似指数Golomb编码。
    类别ID:一元码编码
    类内索引:采用定长码
    【数据压缩(八)】JPEG原理分析及JPEG解码器的调试_第5张图片
  • DC系数Huffman编码举例:
    【数据压缩(八)】JPEG原理分析及JPEG解码器的调试_第6张图片

②AC系数的Huffman编码

  • 在JPEG和MPEG编码种规定:(run, level)表示连续run个0,后面跟值为level的系数。
  • 编码时,run最大为15,用4位表示RRRR;level编码类似DC,分成16个类别,用4位表示,SSSS表示类别号,再加上类内索引进行编码。对(RRRR,SSSS)联合用Huffman编码;对类内索引采用定长编码。
  • AC系数Huffman编码举例:【数据压缩(八)】JPEG原理分析及JPEG解码器的调试_第7张图片

2、JPEG文件格式

(1)Segment的组织形式

JPEG在文件中以Segment的形式组织 ,它具有以下特点:

  • 均以0xFF开始,后跟1byte的Marker和2byte的Segment length(包含表示Length本身所占用的2byte,不含0xFF+Marker所占用的2byte);
  • 采用 Motorola序(相对于Intel序),即保存时高位在前,低位在后;
  • Data部分中,0xFF后若为0x00,则跳过此字节不予处理。

(2)JPEG的Segment Market

【数据压缩(八)】JPEG原理分析及JPEG解码器的调试_第8张图片

【数据压缩(八)】JPEG原理分析及JPEG解码器的调试_第9张图片

三、实验步骤

0、程序准备

遵循程序要求,在调试属性内设定好命令参数。

  • 第一个参数为要解码的jpg文件;
  • 第二个参数为功能选项,此处选择yuv420p,即转换为yuv420格式的文件;
  • 第三个参数为输出文件。

【数据压缩(八)】JPEG原理分析及JPEG解码器的调试_第10张图片

1、运行JPEG解码程序,并输出可供YUVviewer观看的YUV文件

观察调试解码程序发现,Y、U、V分量输出过程在如下所示的函数内,在//输出yuv文件后增加一段程序输出YUV文件。再次运行程序。

/**
 * Save a buffer in three files (.Y, .U, .V) useable by yuvsplittoppm
 */
static void write_yuv(const char* filename, int width, int height, unsigned char** components)
{
	FILE* F;
	char temp[1024];
	snprintf(temp, 1024, "%s.Y", filename);
	F = fopen(temp, "wb");
	fwrite(components[0], width, height, F);
	fclose(F);
	snprintf(temp, 1024, "%s.U", filename);
	F = fopen(temp, "wb");
	fwrite(components[1], width * height / 4, 1, F);
	fclose(F);
	snprintf(temp, 1024, "%s.V", filename);
	F = fopen(temp, "wb");
	fwrite(components[2], width * height / 4, 1, F);
	fclose(F);
	//输出yuv文件
	snprintf(temp, 1024, "%s.yuv", filename);
	F = fopen(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);
}

运行完成后在根目录中得到:
【数据压缩(八)】JPEG原理分析及JPEG解码器的调试_第11张图片
用YUVviewer观看:
【数据压缩(八)】JPEG原理分析及JPEG解码器的调试_第12张图片

2、程序调试过程的理解

(1)理解程序设计的整体框架

【数据压缩(八)】JPEG原理分析及JPEG解码器的调试_第13张图片

(2)理解三个结构体的设计目的

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;		//8x8块使用的量化表
  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数据流结构体。

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

};

(3)理解在视音频编解码调试中TRACE的目的和含义

TRACE活动预处理器块,用来协助程序的调试。在本程序的头文件tinyjpeg.h中将TRACE设为1,表示程序正常调试运行,若想关闭,可设为0。

#define TRACE 1//add by nxn

3、输出量化矩阵和Huffman码表

在头文件tinyjpeg.h中声明要输出的文件:

FILE* qfile;//量化矩阵txt文件
FILE* hfile;//Huffman码表txt文件

(1)量化矩阵

  1. 在创建量化矩阵的函数build_quantization_table()中添加量化矩阵输出代码;
	//输出所有量化矩阵
	qfile = fopen("quan.txt", "a");
	for (i = 0; i < 8; i++) {
		for (j = 0; j < 8; j++) {
			fprintf(qfile, "%d\t", ref_table[*zz]);
			*qtable++ = ref_table[*zz++] * aanscalefactor[i] * aanscalefactor[j];
		}
		fprintf(qfile, "\n");
	}
  1. 在运用此函数的地方,即量化表解析函数parse_DQT()中添加代码进行量化矩阵文件的更新写入。
#if TRACE
	fprintf(p_trace, "< DQT marker\n");
	fflush(p_trace);
	//更新打印量化矩阵
	fprintf(qfile, "DQT ID: %d\n", qi);
	fflush(qfile);
#endif

(2)Huffman码表

  1. 在Huffman码表创建的地方即函数build_huffman_table()内添加代码打印输出Huffman码表。
if TRACE
		fprintf(p_trace, "val=%2.2x code=%8.8x codesize=%2.2d\n", val, code, code_size);
		fflush(p_trace);
		fprintf(hfile, "val=%2.2x code=%8.8x codesize=%2.2d\n", val, code, code_size);
		fflush(hfile);
#endif
  1. 在Huffman码表解析的地方,即函数parse_DHT()中添加代码实现输出Huffman码表的分类(DC或AC及序号)。
//输出huffman码表
	hfile = fopen("huff.txt", "a");
	while (length > 0) {
		index = *stream++;

		/* We need to calculate the number of bytes 'vals' will takes */
		huff_bits[0] = 0;
		count = 0;
		for (i = 1; i < 17; i++) {
			huff_bits[i] = *stream++;
			count += huff_bits[i];
		}
#if SANITY_CHECK
		if (count >= HUFFMAN_BITS_SIZE)
			snprintf(error_string, sizeof(error_string), "No more than %d bytes is allowed to describe a huffman table", HUFFMAN_BITS_SIZE);
		if ((index & 0xf) >= HUFFMAN_TABLES)
			snprintf(error_string, sizeof(error_string), "No more than %d Huffman tables is supported (got %d)\n", HUFFMAN_TABLES, index & 0xf);
#if TRACE
		fprintf(p_trace, "Huffman table %s[%d] length=%d\n", (index & 0xf0) ? "AC" : "DC", index & 0xf, count);
		fflush(p_trace);
		fprintf(hfile, "Huffman table %s[%d] length=%d\n", (index & 0xf0) ? "AC" : "DC", index & 0xf, count);
		fflush(hfile);

(3)输出结果

量化矩阵(0为DC,1为AC):
【数据压缩(八)】JPEG原理分析及JPEG解码器的调试_第14张图片

Huffman码表(展示部分):
【数据压缩(八)】JPEG原理分析及JPEG解码器的调试_第15张图片

四、实验结论

通过本次实验:

  1. 掌握了JPEG编解码系统的基本原理。
  2. 成功调试了复杂的数据压缩算法实现的代码。
  3. 最后根据代码理解进行了一定的修改,实现了实验要求的数据输出。

你可能感兴趣的:(数据压缩,人工智能,深度学习)