【实验五】JPEG解码

来源:互联网 发布:军事新闻软件哪个好 编辑:程序博客网 时间:2024/06/07 22:14

一、实验原理

1.JPEG简介:

JPEG是Joint PhotographicExperts Group(联合图像专家小组)的缩写,是第一个国际图像压缩标准。JPEG图像压缩算法能够在提供良好的压缩性能的同时,具有比较好的重建质量,被广泛应用于图像、视频处理领域。

根据人眼的视觉特性,人眼对亮度信息比色度信息敏感,对低频信息比高频信息敏感。首先对色度信息进行下采样。另外,将空间域的亮度色度信息经DCT变换到频域,对亮度信息细量化、色彩信息粗量化,对低频信息细量化、高频信息粗量化。再对量化结果进行变长编码,达到压缩图片的目的,同时主观上图片质量不甚下降。

2.JPEG编码:


下采样:为实现压缩,对色度信息进行下采样,由原4:4:4的格式变为4:2:2或4:2:0格式或不进行下采样。

分块:将图像分成(8*8)的块以便进行DCT变换,不够的要取边缘像素补齐

零偏置:零偏置,对于灰度级是2n的像素,通过减去2n-1,将无符号的整数值变成有符号数,对于n=8,即将0~255的值域,通过减去128,转换为值域在-128~127之间的值,使像素的绝对值出现3位10进制的概率大大减少。

DCT:经过DCT变换后,图像中的低频分量会集中在左上角,由于图像低频能量高,故而左上角数值大,右下角有较多的0值。

量化:人眼对低频敏感,对高频不敏感。所以低频细量化,高频粗量化;人眼对亮度信号敏感,对色度信号不敏感。所以亮度和色度分量分别采用不同的量化表。

之字形扫描:游程编码的扫描过程,由于DCT变换后,越往右下角的分量越小甚至为0,于是采用之字形扫描。将二维降到一维后会在高频部分出现连0,由此可以提高编码效率。

熵编码:利用相邻块之间DC系数的空间相关性,对DC系数进行DPCM编码,即当前块的DC系数减去前一块的DC系数后编码。对AC系数进行游程编码(Run-Length Ecoding)。

 

3.JPEG解码

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

均以0xFF开始,后跟1byteMarker2byteSegmentlength(包含表示Length本身所占用的2byte,不含”0xFF+Marker”所占用的2byte

采用Motorola序(相对于Intel序),即保存时高位在前,低位在后。

JPEG图像格式介绍:

缩写

名称

说明

标记代码

字节数

SOI

Start of Image

图像开始

固定值0xFFD8

2(标记代码)

EOI

End of Image

图像结束

固定值0xFFD9

2(标记代码)

APP0

Application

应用程序保留标记

固定值0xFFE0

variable

DQT

Define Quantization Table

定义量化表

固定值0xFFDB

variable

SOF0

Start of Frame

帧图像开始

固定值0xFFC0

variable

DHT

Define Huffman Table

定义哈夫曼表

固定值0xFFC4

variable

SOS

Start of Scan

扫描开始

固定值0xFFDA

variable

解码流程:

(1)读取文件

(2)解析Segment Marker 
*
解析SOI

*解析APP0 
      
检查标识”JFIF”及版本 
      
得到一些参数

*解析DQT 
      
得到量化表长度(可能包含多张量化表) 
      
得到量化表的精度 
      
得到及检查量化表的序号(只能是0~3 
      
得到量化表内容(64个数据)

*解析SOF0 
      
得到每个sample的比特数、长宽、颜色分量数 
      
得到每个颜色分量的ID、水平采样因子、垂直采样因子、使用的量化表序号(与DQT中序号对应)

*解析DHT 
      
得到 Huffman表的类型(ACDC)、序号 
      
依据数据重建 Huffman

*解析SOS 
      
得到解析每个颜色分量的DCAC值所使用的Huffman表序号(与DHT中序号对应)(3)依据每个分量的水平、垂直采样因子计算MCU的大小,并得到每个 MCU 8*8宏块的个数。

(4)对每个MCU解码(依照各分量水平、垂直采样因子对MCU中每个分量宏块解码)。
*对每个宏块进行Huffman解码,得到DCT系数

*对每个宏块的DCT系数进行IDCT,得到YCbCr

*遇到 Segment Marker RST时,清空之前的 DC DCT系数

(5)解析到 EOI,解码结束

(6)YCbCr转化为需要的色彩空间并保存。

 

二、主要代码分析

(1)理解struct huffman_table、struct component、struct jdec_private三个结构体的设计目的:

jdec_private:用于存储JPEG的基本信息,如图像宽高、数据流指针、量化表、霍夫曼码表、IDCT后的亮色通道值等等等诸多信息。包含component结构体和huffman_table结构体

component:解码时,该结构体来储存当前宏块的所用解码信息,经解码后的8x8DCT系数矩阵。  

 huffman_table:存放重建后的Huffman码表。

(2) 将输出文件保存为可供YUVViewer观看的YUV文件。

static void write_yuv(const char *filename, int width, int height, unsigned char **components){  FILE *F,*acfile,*dcfile;  char temp[1024];  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);  acfile = fopen(acfilename, "wb");  dcfile = fopen(dcfilename, "wb");  fwrite(outDCbuf, width * height *3 /64 , 1, dcfile);//直流分量文件  fwrite(outACbuf, width * height *3 /64 , 1, acfile);//交流分量文件  fclose(acfile);  fclose(acfile);} 

(3) 

/*tinyjpeg.h*/FILE *c_file;//输出表格的文件指针FILE *acfile ;// AC图像FILE *dcfile ;// DC图像static char out_str[20];// c_file中输出的字符串static unsigned char *outDCbuf = NULL;// 为DC图像开缓冲区static unsigned char *outACbuf = NULL; 为AC图像开缓冲区#define ACNUM 2//提取的AC图像所在的DCT的位置索引#define C_TABLE 1#define C_FILENAME "table.txt"#define acfilename "ac.yuv"#define dcfilename "dc.yuv"/*main*/#if C_TABLE  c_file = fopen(C_FILENAME,"w");  if(c_file == NULL)  {   printf("table file open error!");  }#endif

(4)提取量化表。

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};/*build_quantization_table*///get the Q table#if C_TABLE  snprintf(out_str, sizeof(out_str),"%d", ref_table[*(zz-1)]);  //zz按照zigzag索引  fprintf(c_file,"%s\t",out_str);  if(j == 7)   fprintf(c_file,"\n\n");  fflush(c_file);#endif

(5)提取Huffman表。在build_huffman_table函数中仿照了TRACE直接在函数中将val,code和codesize输出到了txt中。

#if C_TABLE     fprintf(c_file,"val=%2.2x code=%8.8x codesize=%2.2d\n", val, code, code_size);  fflush(c_file);#endif#if C_TABLE     fprintf(c_file,"\n\n");  fflush(c_file);#endif

(6)提取DC和AC系数输出图像。

具体数值从component结构体里的DCT中直接提取的。写U,V直接在Y的基础上分别加上1倍和2倍图像size的办法找到对应的位置。重建DC、AC系数后,其值不在0~255范围内,所以需要将它的值映射到0~255范围内,再作为亮度信息写入输出的YUV文件。

/*tinyjpeg_decode*/  //DC  *(outDCbuf + dct_count) = (unsigned char)((priv->component_infos[cY]).DCT[0]/8 +128);  *(outDCbuf + dct_count + priv->height * priv->width /64) =    (unsigned char)((priv->component_infos[cCb].DCT[0])/8 + 128) ;//U  *(outDCbuf + dct_count + 2 * priv->height * priv->width /64) =    (unsigned char)((priv->component_infos[cCr].DCT[0])/8 + 128) ;//V  //AC:  *(outACbuf + dct_count) = (unsigned char)((priv->component_infos[cY]).DCT[ACNUM] +128 );  *(outACbuf + dct_count + priv->height * priv->width /64) =    (unsigned char)((priv->component_infos[cCb]).DCT[ACNUM] +128 );  *(outACbuf + dct_count + 2 * priv->height * priv->width /64) =    (unsigned char)((priv->component_infos[cCr]).DCT[ACNUM] +128 );
三、实验结论
(1)输出图像直流dc.yuv  交流ac.yuv

(2)table.txt

(3)概率分布








原创粉丝点击