图像压缩编码——JPEG
在JPEG中的数据处理单元是
8x8
block
在JPEG中编码器和解码器是互逆
的,因此在编解码过程中提供的表说明完全一致
数据格式-YUV
标准色彩空间:一个或三个组件。 对于三个组件,YCbCr
编码
解码
DCT变换
在计算FDCT之前,对应输入数据进行层平移
处理,即把输入数据变成带符号的2的补码表示。对于8位输入精度,层平移通过减128
来完成。
- FDCT:
$F(u, v) = \dfrac{1}{4}c(u)(v)\left[\sum_{i=0}^{7}\sum_{j=0}^{7}f(i, j)\cos\dfrac{(2i+1)u\pi}{16}\cos\dfrac{(2j+1)v\pi}{16}\right]$
- IDCT:
$f(i, j) = \dfrac{1}{4}c(u)c(v)\left[\sum_{u=0}^{7}\sum_{v=0}^{7}F(u, v)\cos\dfrac{(2i+1)u\pi}{16}\cos\dfrac{(2j+i)v\pi}{16}\right]$
$Cu, Cv = 1/\sqrt{2}$ 为 $u, v = 0$
$Cu, Cv = 1$ 除此以外
量化
所谓量化就是用像素值
÷量化表对应值
所得的结果。由于量化表左上角的值较小,右上角的值较大,这样就起到了保持低频分量,抑制高频分量的目的。
Y分量代表了亮度信息,UV分量代表了色差信息,因此量化表通常两张。
- 编码时
$Sq_{vu}=round\left(\dfrac{S_{vu}}{Q_{vu}}\right)$
- 解码时
$R_{vu} = Sq_{vu} \times Q_{vu}$
量化表
1 | //亮度分量量化表 |
所谓JPEG的有损压缩,损的是量化过程中的高频部分; 因为对于人眼而言
低频部分比高频部分要重要得多
8×8块样本与DCT系数的关系
编码分类
- 一类是每个88格子中的[0,0]位置上元素,即
DC
(直流分量),代表88个子块的平均值,采用差分编码DPCM
- $DIFF = DC_i - PRED$
- 在扫描行和每个重启动间隔的开始时,将DC系数的预测值(PRED)初始化为
0
.
- 二类是每个8*8格子中的其余63个元素,即
AC
(交流分量),采用行程编码RLE
- 为了保证低频分量先出现,高频分量后出现,以增加行程中连续“0”的个数,这63个元素采用了“Z”字型(Zig-Zag)的排列方法
- 如果“Z”序列中的剩余系数全为0,那么可直接使用块结束符(EOB)进行编码
zigzag
熵编码
熵编码指熵保持编码,编码时,平均信息量保持不变。
Huffman编码
- 对出现频率较高的符号,设计较短的码字,反之,用最长的码字
- Huffman编码表事先定义好
编码表
- 亮度
Y
的DC
huffman码表 - 色度
U\V
的DC
huffman码表 - 亮度
Y
的AC
huffman码表 - 色度
U\V
的AC
huffman码表
JPEG Huffman Coding Table
编码表的生成:https://raw.githubusercontent.com/Winddoing/CodeWheel/master/jpeg/jpeg_huffman_ac_dc_table.c
主要生成EHUFSI
和EHUFCO
两类表
1 | 亮度DC系数: |
编码流程
编码过程是根据一组扩展表XHUFCO
和XHUFSI
定义的,它们包含所有可能差值的完整霍夫曼CODE和SIZE集合
DC系数Huffman编码
1 | SIZE = XHUFSI(DIFF) |
XHUFSI和XHUFCO从编码器表
EHUFSI
和EHUFCO
产生, 使用DIFF作为两个表的索引。
代码实现:
1 | /* Encode the DC coefficient difference per section F.1.2.1 */ |
libjpeg-turbo: jchuff.c
AC系数Huffman编码
ZZ中的每个非零AC系数由一个复合的8位值RS描述:
1 | RS = binary ’RRRRSSSS’ |
- 后面4个低有效位(
SSSS
)为ZZ中下一个非0系数的幅值定义类别 - 前面4个高有效位(
RRRR
)给出ZZ中相对与先前非0系数位置(也就是非0系数之间的0系数行程)
由于0系数的行程可能超过15,故定义值’RRRRSSSS‘ = ’0xf0‘
来表示行程为15的0系数组,后跟一0幅值的系数。另外,特殊值’RRRRSSSS’ = ‘00000000’
用于对块结束符EOB
进行编码(当块中的所有剩余系数为0时)。
示例:8x8block
一个8x8的量化后的亮度块,已完成zigzag排序:
1 | 系数: 12 5 -2 0 2 0 0 0 1 0 -1 0 |
DC系数编码
1 | DIFF = 12; //'1100b' |
AC系数编码
- ZZ(1) = 5: 它与ZZ(0)之间无0系数R=0,RRRR=0;幅值5落入第3类,SSSS=3;即’RRRRSSSS‘ = ’0/3‘。查AC Huffman编码表为
100
。幅值5的编码为101
,故ZZ(1)的编码为100101
1 | ZZ(1) = 5; //'101b' |
- ZZ(2) = -2, ‘RRRRSSSS’ = ‘0/2’, 查AC Huffman编码表是
01
,幅值-2落入第2类,ZZ(2) - 1 = -3, -3用补码表示并取后两位
(-2除去符号位占两个位宽)为01
, 因此ZZ(2)的编码0101
- ZZ(3) = 0
- ZZ(4) = 2, 编码:
1101110
1 | ZZ(4) = 2; //10b |
- ZZ(5) ~ ZZ(7) = 0
- ZZ(8) = 1, 编码:
1110101
- ZZ(0) ~ ZZ(30) = 0, ZZ(31) = -1;由于RRRR=22 > 15,故先编一个F/0,huffman编码为
11111111001
。然后RRRR=22 - 16 = 6,这时RRRRSSSS=6/1, Huffman编码1111011
;幅值-1在第1类,取(-1-1=-2)补码的最后一位0
,最后编码11110110
- ZZ(32) ~ ZZ(63) = 0,直接用一个EOB(0/0)结束,编码
1010
JPEG文件
文件结构
JPEG的每个标记都是由 2个字节组成,其前一个字节是固定值0xFF
,每个标记之前还可以添加数目不限的0xFF填充字节(fill byte)
标记 | 数值 | 作用 |
---|---|---|
SOI(Start Of Image) | 0xD8 | 图像开始 |
APP0 | 0xEO | JFIF应用数据块 |
APPn | 0xE1 ~ 0xEF | 其他的应用数据块(n, 1~15) |
DQT | 0xDB | 量化表 |
SOF0(Start Of Frame) | 0xC0 | 帧开始 |
DHT | 0xC4 | 霍夫曼(Huffman)表 |
SOS | 0xDA | 扫描线开始 |
EOI | 0xD9 | 图像结束 |
jpeg文件解析示例
1 | Frame 1: 345637 bytes on wire (2765096 bits), 345637 bytes captured (2765096 bits) |
wireshark解析
参考
- itu-t81.pdf —— 图像数字压缩和编码
- JPEG图像编码
- JPEG File Interchange Format,JFIF