实验五 JPEG原理分析及JPEG 解码器的调试
来源:互联网 发布:魔兽争霸冰封王座mac 编辑:程序博客网 时间:2024/06/03 08:01
一、JPEG简介
1、JPEG简介
JPEG(Joint Photographic Experts Group)是国际电信联盟(International Telecommunication Union,ITU)、国际标准化组织(International Organization for Standardization,ISO)和国际电工委员会(International Electrotechnical Commission,IEC)共同制定的第一个国际图像压缩标准。JPEG图像压缩算法能够在提供良好的压缩性能的同时,具有比较好的重建质量,被广泛应用于图像、视频处理领域,网站上80%的图像都采用了JPEG压缩标准。
2、JPEG文件格式
(1)peg在文件中以segment的形式组织,有以下特点:每个segment均以OXFF开始,后跟1bit的marker和2bit的segmentlength(包含segmentlength本身所占的2bit,不含0xFF以及marker所占的2bit)。
每个marker对应的意思如下:
(2)采用大位字节序,高位在前,低位在后
(3)data部分中,若0xFF 后面是00,则跳过不读
2.文件内容
SOI:(FFD8)图像开始 APPO:应用程序保留标记 (版本参数信息)
DCT量化表 :量化表长度、量化精度、量化表ID、表项(长度为64bit(8位精度),记录了8*8DCT变换后每个像素的量化步长,由于DC、AC、亮度、色度使用不同的量化编,所有量化表最多有4个)
SOFO 帧图像开始:记录每一帧图像的数据长度、样本数据的位数、图像的高度、图像的宽度、颜色分量数(JFIF使用YCbCr)、颜色分量信息(分量ID(Y、U、v)、采样因子(4:4:4、4:2:2、4:2:0)、量化表ID)
DHT(定义huffman码表):表长度、表ID(0:亮度 1:色度)、表类型(0:直流 1:交流)不同位数的码字数量(16字节分别记录了长度为1到16的码字的个数)、权值
DC表:权值的大小直流分量数值的二进制位数,读取后经过查表查得对应的DC值。权值的字节数为DC经DPCM编码后码字个数的总和
AC表:权值的高四位表示当前数值前面有多少个0,低4为表示交流分量数值的二进制位数。
SOS扫描开始:数据长度、颜色分量数(与SOF0相同)、颜色分量信息(颜色分量ID:1 2 3对应Y U V)、表号:(高位为直流系数使用的hufman表数、低位为交流系数使用的huffman表数)、压缩图像数据
EOI:(FFD9)图像结束
二、JPEG编解码原理
1.jpeg编码原理
(1)编码原理
(2)流程分析
a.图像预处理:
将输入图像分成若干个8*8的小块儿。在此过程中需对图像的宽和高进行剪切,使其都为8的倍数,不足的部分复制与其最近的像素值。目的是方便进行8*8DCT变换
将原像素值减去128,使像素值在-128~128之间,目的是减少像素值达到3位数(十进制)的概率。像素值越大,量化后所需的码字越长,不利于编码的有效性。
b.DCT
作用:能量守恒:经DCT变换前后,图像的 能量不变
能量集中:经DCT变换后,能量集中在左上角
去相关:经DCT变化后,图像的相关性减少,有利于提高后续huffman编码的有效性;从信息论的角度来说,若不去相关,总的量化失真不能写成隔值之和。
由于人眼对低频敏感,高频不敏感,经DCT变化后,多数低频信息集中在左上角,且数值较大,相关性较小,只需对左上角的值进行细量化,能在保证图像质量的同时提高压缩比。
c.量化(中平型量化器)
量化步距根据系数所在的位置和颜色分量来定,Y分量和左上角位置的系数步距小,UV分量和右下角位置的分量步距大
由于人眼对亮度信号比对色度信号更敏感,因此使用了两种量化表:亮度量化值(量化步距小)和色度量化值(量化步距小)
由于人眼对低频敏感,高频不敏感,因此对低频分量采用细量化,高频分量采用粗量化。(如果原始图像细节比较丰富,则量化后去掉的数据多了,差距较大。细节越少的图量化误差越小)
d.编码
DC系数:差分编码
8*8图像块经过DCT变换后,得到的直流系数有两个特点:数值大、相邻数值变化不大。
根据这个特点,JPEG对DC系数进行差分脉冲调制编码(DPCM)(其中,相邻DC系数之差不在进行量化),对相邻图像块之间的量化DC之差DIFF进行huffman编码。
编码方法:
码字由两部分组成:类别ID+类内索引
将每一个DIFF经查下表,判断出在哪一个范围内,记下类别ID,作为码字的第一部分,DIFF的真值作为码字的第二部分。
AC系数:游程编码
先将数据之字形扫描,将二位数据扫描成一维数据,定义(run,level)结构,来对此一维数据编码。其中,run表示非0数据前0的个数,level表示非0数据的值。
run的最大值为1个,用RRRR表示,level的编码类似DC 系数,先分为16个类别,用4位SSSS表示,再查类内索引(用定长码编码)。
即交流huffman码字的前四位表示0的个数,后四位表示该交流分量数值的二进制位数,也即接下来需要读入的位数。
(3)性能、误差分析
蚊子噪声(波纹效应):由于对高频信号做DCT后进行滤波产生。高频信息经JPEG压缩,量化步长大时,DCT系数判为0的概率增加,频域高频截止,时域有较长拖尾u,表现在图像上就是蚊子噪声。
块效应:由于DCT系数量化时,每个块的量化误差不同,导致相邻块之间边沿的不连续性。
轮廓线:
2.jpeg解码流程
(1)读取文件
(2)解析segmentmarker
依次解析出SOI、APPO、DCT、SCF0、DHT、SOS、EOI
(3)依据每个分量的水平采样、垂直采样因子计算MCU(微控制单元,即RAM,即要开辟的图像内存?)的大小,并得到每个MCU中8*8宏块的个数。
(4)对每个MCU解码
对每个宏块进行huffman解码得到DCT系数,进行IDCT得到变换之前的数据。
(5)解析到EOI,解码结束
(6)将得到的Y、Cb、Cr转换成需要的色彩空间并保存。
二、实验步骤
1.逐步调试JPEG解码器程序。将输入的JPG文件进行解码,将输出文件保存为可供 YUVViewer观看的YUV文件。
在write_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[1], width*height/4, 1, F); fclose(F);2. 程序调试过程中,应做到:
- 理解程序设计的整体框架
- 理解三个结构体的设计目的
struct huffman_table :用来存放huffman解码后的DC、AC系数
struct component :用来存放IDCT反变化后的颜色分量
struct jdec_private :用来统筹整个解码过程,包括huffman_table,component
- 理解在视音频编解码调试中TRACE的目的和含义 :trace用来记录解码过程,存放每个解码步骤完成后得到数据
- 会打开和关闭TRACE
在loadjpeg.c的主函数中,以下代码用来打开trace文件:
#if TRACE p_trace=fopen(TRACEFILE,"w");//p_trace是追踪文件 if (p_trace==NULL) { printf("trace file open error!"); }#endif以下代码用来关闭文件:
#if TABLES fclose(hufftable);#endif
- 会根据自己的要求修改TRACE
在解码过程的每一步都将得到的数据写入trace.file,可在此时更改要写入的trace。例如,将文件的水平、垂直采样因子写入trace的过程如下:
#if TRACE fprintf(p_trace,"Component:%d factor:%dx%d Quantization table:%d\n", cid, c->Hfactor, c->Hfactor, Q_table ); fflush(p_trace);#endif
3. 以txt文件输出所有的量化矩阵和所有的HUFFMAN码表。
(1)输出量化矩阵:
仿照trace文件的写入写出方法:首先在tinyjpeg.h中加入:
...FILE *octtable;//add by zsy...#define TRACE 1//add by nxn#define OCTTABLES 1 //add by zsy#define OCTFILE "oct_jpeg.txt"//add by zsy
在loadjpeg.c中打开和关闭octtable:
//打开octtable文件#if OCTTABLES //octtable=fopen(OCTFILE,"w");//octtable用来输出量化表 //if (octtable==NULL) //{ // printf("octtable file open error!"); //}//只能处理输入一张图片 snprintf(temp, 1024, "%s.txt", output_filename); octtable = fopen(temp, "wb");//输入多张图片#endif//关闭octtable文件#if OCTTABLES fclose(octtable);#endif在parse_DQT(priv, stream)中记下量化表标号: qi = *stream++;//huffman表ID #if OCTTABLES//add by zsy,输出量化表IDfprintf(octtable,"DQT ID:%d\n",qi);fflush(octtable);#endif
在build_quantization_table(table, stream)中得到量化矩阵:
for (i=0; i<8; i++) { for (j=0; j<8; j++) { fprintf(octtable,"%d\t",ref_table[*zz]); //add by zsy*qtable++ = ref_table[*zz++] * aanscalefactor[i] * aanscalefactor[j];//以zig序将量化表存储 } fprintf(octtable,"\n");//add by zsy }
文件的定义,在主函数中的打开和关闭与上述相同。
在parse_DHT 中,输出huffman表类型和表ID:
if (index & 0xf0 )//index&0xf0 位index的高四位,1代表AC表,0代表DC表 {//记录AC表ID add by zsy#if HUFFTABLESfprintf(hufftable,"hufftable AC %d号表\n",index&0xf);//index&0xf,index的低四位,代表表号#endif build_huffman_table(huff_bits, stream, &priv->HTAC[index&0xf]);//得到AC系数 } else //记录AC表ID add by zsy#if HUFFTABLESfprintf(hufftable,"hufftable DC %d号表\n",index&0xf);#endif build_huffman_table(huff_bits, stream, &priv->HTDC[index&0xf]); 在build_huffman_table中输出huffman码表: #if HUFFTABLES//add by zsy fprintf(hufftable,"val=%2.2x\tcode=%8.8x\tcodesize=%2.2d\r\n", val, code, code_size); fflush(hufftable); #endif
4. 输出DC、AC图像并经过huffman统计其概率分布(使用第三个实验中的Huffman编码器)。
在loadjpeg.c中敌营DC、AC图像文件、指向文件的指针、以及Buf
FILE *DCimage; FILE *ACimage; float *DC=NULL; unsigned char *DCBuf=NULL; unsigned char *ACBuf=NULL;在main函数中开空间、打开关闭文件:
DCFileName = argv[4]; DCimage=fopen(DCFileName,"wb"); ACFileName = argv[5]; ACimage=fopen(ACFileName,"wb");
DC = (float*)malloc(1024 * 1024); DCBuf=(unsigned char *)malloc(1024 * 1024); ACBuf=(unsigned char*)malloc(1024 * 1024);在tinyjpeg中输出huffman表ID:
if (index & 0xf0 ) {//记录AC表ID add by zsy#if HUFFTABLESfprintf(hufftable,"hufftable AC %d号表\r\n",index&0xf);//index&0xf,index的高四位,代表AC表号#endifbuild_huffman_table(huff_bits, stream, &priv->HTAC[index&0xf]);} else { //记录DC表ID add by zsy#if HUFFTABLESfprintf(hufftable,"hufftable DC %d 号表\r\n",index & 0xf);#endif build_huffman_table(huff_bits, stream, &priv->HTDC[index&0xf]); }在build_huffman_table中输出huffman表:
#if HUFFTABLES//add by zsy fprintf(hufftable,"val=%2.2x\tcode=%8.8x\tcodesize=%2.2d\r\n", val, code, code_size);
fflush(hufftable);5. 观察蚊子噪声
四、实验结果
1.量化矩阵
2、huffman表:
3、DC\AC图像
DC图像:DCT[0]
AC 图像: DCT[1] DCT[2] DCT[3]
4.蚊子噪声
五、总结1、由DC、AC图像可以看出,DC图像基本保留了原图的细节,而AC图像随着AC系数的减小图像也越来越模糊。
2、整个jpeg解码程序短小精悍,值得细细品味。整个程序顺下来犹如读了一本好书,荡气回肠。
3、其中有些地方还没有弄懂,相信以后写程序的时候还会回来再看几遍。
- 实验五 JPEG原理分析及JPEG 解码器的调试
- 实验五 JPEG原理分析及JPEG解码器的调试
- 实验五 JPEG原理分析及JPEG解码器的调试
- 数据压缩实验五 JPEG原理分析JPEG解码器的调试
- 数据压缩 实验五 JPEG原理分析 JPEG解码器的调试
- 数据压缩 实验五 JPEG原理分析JPEG解码器的调试
- 【实验六】JPEG原理分析及JPEG解码器的调试
- 数据压缩原理与应用 实验五 JPEG 原理分析及 JPEG 解码器的调试
- 数据压缩原理 实验五 JPEG原理分析及JPEG解码器的调试
- 数据压缩实验五 JPEG原理分析及JPEG解码器的调试
- 数据压缩实验五——JPEG原理分析及JPEG解码器的调试
- JPEG原理分析及JPEG解码器调试
- 【数据压缩】JPEG原理分析及JPEG解码器的调试
- JPEG 原理分析及 JPEG 解码器的调试
- 苏泊尔耗的JPEG解码器[五(完)]
- 【实验五】JPEG解码
- 实验五:JPEG解码
- 实验五 JPEG解码
- 并发世界的2个重要定律Amdahl、Gustafson定律
- struts2--实现Excel上传并解析
- Android自定义控件
- 【6.6】c++ primer plus 课后编程答案
- 怎样理解阻抗匹配?
- 实验五 JPEG原理分析及JPEG 解码器的调试
- 曾经觉得学习晦涩难懂的我是如何爱上linux
- Awk实现句子按词反序输出
- C语言位操作
- 【MongoDB】设置环境变量及配置成Windows服务
- 二叉树相关问题
- HTML5基本属性
- java:类的构造方法
- 设计模式--代理模式