文章目录
1.实验名称
JPEG原理分析及JPEG解码器的调试
2.实验目的
掌握JPEG编解码系统的基本原理。初步掌握复杂的数据压缩算法实现,并能根据理论分析需要实现所对应数据的输出。
3.主要设备
安装Windows和Visual Studio软件的个人计算机
4.实验内容
4.1 JPEG文件格式
依次 | 文件格式 | 标记代码 | 具体字段 |
---|---|---|---|
① | SOI(图像开始) | 0xFFD8 | ----------------------------------- |
② | APP0(应用程序保留标记0) | 0xFFE0 | ![]() |
③ | DQT(定义量化表) | 0xFFDB | ![]() |
④ | SOF0(帧图像开始) | 0xFFC0 | ![]() |
⑤ | DHT(定义哈夫曼表) | 0xFFC4 | ![]() |
⑥ | SOS(扫描开始) | 0xFFDA | ![]() |
⑦ | EOI(图像结束 2字节) | 0xFFD9 | ------------------------------------- |
根据上表,用FlexHEX打开一张JPG格式的图片,并用红笔标注出每个标记代码:
依次验证每一字段,发现的确如此。
4.2 JPEG编解码原理
4.2.1 编码流程
①零偏置
目的:保证输入图像的采样有近似地集中在零附近的动态范围。
实现方法:对于灰度级是 2 n 2^n 2n的像素,通过减去 2 n − 1 2^{n-1} 2n−1,将无符号的整数值变成有符号数.
② 8 ∗ 8 8*8 8∗8 DCT变换
目的:实现能量集中和去相关,便于去除空间冗余,以达到压缩图像数据的目的。
实现方法:首先对图像进行 8 ∗ 8 8*8 8∗8的分块(若图像的宽高不是8的倍数,可对图像进行补0,补至8的倍数),之后进行DCT(离散余弦变换)变换,经DCT变换后, 8 ∗ 8 8*8 8∗8的图像块将变为 8 ∗ 8 8*8 8∗8的DCT系数块。
DCT变换计算公式:
其中
③量化
利用人眼对高频细节不甚敏感的特性,对高频的AC分量进行粗量化,对低频的DC分量进行细量化。
利用人眼对色度细节不甚敏感的特性:对色度分量进行粗量化,对亮度分量进行细量化。
JPEG算法提供了两张标准的量化系数矩阵:
标准亮度量化表
标准色差量化表
④编码
对DC系数:差分编码
由于直流系数 F(0,0)反映了该子图像中包含的直流成分,通常较大,又由于两个相邻的子图像的直流系数通常具有较大的相关性,所以对 DC 系数采用差值脉冲编码(DPCM),即对本像素块直流系数与前一像素块直流系数的差值进行无损编码。
对AC系数:游程编码
首先对AC系数的之字形扫描
出现很多连零,使用游程编码。最后如果都是零,给出EOB (End of Block)即可。
⑤Huffman编码
Huffman编码几乎是所有压缩算法的基础,它的基本原理是根据数据中元素的使用频率,调整元素的编码长度,以得到更高的压缩比。JPEG 中共采用了四张 Huffman 码表:亮度 DC、亮度 AC、色度 DC、色度 AC,即分别对图像的亮度和色度,直流和交流数据进行编码处理。
JPEG建立Huffman表的方法:
第一个码字必定为0.
如果第一个码字位数为1,则码字为0
如果第一个码字位数为2,则码字为00
以此类推
从第二个码字开始:
如果它和它前面的码字位数相同,则当前码字为它前面的码字加1;
如果它的位数比它前面的码字位数大,则当前码字是前面的码字加1后再在后边添若干个0,直至满足位数长度为止。
直流系数权值就是解码时再需要读入的bit位数。
交流系数权值的高4位表示当前数值前面有多少个连续的零,低4位表示该交流分量数值的二进制位数,也就是接下来需要读入的位数。
4.2.2 解码流程
5.实验步骤
5.1 逐步调试JPEG解码器程序
5.1.1 理解程序设计的整体框架
1.读取文件
在主函数main函数中,打开输入输出文件,并解析了输出格式:
int main(int argc, char *argv[])
整个JPEG解码过程,由下面的covert_one函数实现:
int convert_one_image(const char *infilename, const char *outfilename, int output_format)
2.解析 Segment Marker(tinyjpeg_parse_header中)
解析文件头:
int tinyjpeg_parse_header(struct jdec_private *priv, const unsigned char *buf, unsigned int size)
解析DQT:
static int parse_DQT(struct jdec_private *priv,