文章目录
一、JPEG编解码原理
编码:
- Level offset:将输入的图像的所有像素点的值-128,使其原先范围由0~255变为-128~127。
- 8×8DCT变换:将零电平偏置之后的图像分成8×8像素的块来处理,不足8×8的,取边缘像素补齐,对每个块做DCT变换,直流系数在每个块的左上角,越右下角的分量频率越高,数值越小。
- Uniform scalar quantization:使用根据人眼视觉特性设计的量化矩阵对DCT变换之后的结果进行量化,减少视觉冗余。
- DC系数编码:由于两个相邻的子图像的直流系数通常具有较大的相关性,所以对 DC 系数采用差分脉冲编码(DPCM)。
- AC系数编码:先对AC系数做之字形扫描,再进行游程编码和huffman编码。
解码:编码的逆过程,最后得到重建图像,但和原图像之间存在误差。
二、JPEG文件格式
在JPEG文件中,数据被分成一个个segment,每一个都由一个marker作为开头标记这个字段的内容。
三、实验过程
1、实验流程
- 读取JPEG流
- 通过tiny_jpeg_parser()函数解析JPEG流中的头部信息(marker)
- tiny_jpeg_decode()函数解码文件,解码流储存在变量jdec中。
检查SOI;检查APP0中的JFIF标识;解析DQT获得量化表内容和序号,解析 SOF0;解析DHT获得 Huffman 表的类型、内容和序号;解析 SOS。 - tiny_jpeg_decode()通过垂直/水平采样因子确定MCU(minimum coding unit)的大小和输入图像的格式,得到每个MCU中8*8的宏块数量。根据不同的MCU的采样频率调用不同的函数进行解码。
(1)对每个宏块进行 Huffman 解码,得到 DCT 系数
(2)对每个宏块的 DCT 系数进行 IDCT,得到 Y、Cb、Cr
(3)每次遇到RSTn时要清空之前的DCT系数。 - 解析到 EOI结束,将 Y、Cb、Cr 转化为需要的色彩空间并保存。
2、实验步骤
1.调试JPEG解码器程序,输出.YUV文件
修改write_yuv函数以输出YUV文件
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");<