JPEG2000
的实现
kakadu
中是用一个
16
位数来表示失真长度曲线的斜率;在整个编码过程中,使用斜率值的右移四位的标量量化值。
编码的分配表面是按照块进行的,实际并是整个压缩过程考虑的。
JPEG2000
使用一个
4096
元素的量化斜率值数组来存储压缩过程中遇到的斜率值(
quant_slope_rates
)。
当第一次编码的时候,从
4096
个元素找满足码率的斜率下限,实际上这个时候没有任何压缩,数组的所有元素都为
0
;所以开始的时候得到的斜率值是
1
。第一个
block
使用斜率值
1
作为块编码的依据。
码块编码需要两个关于度量失真的参数:
wmse
和失真斜率。编码为每个编码过程定义了一个
pass_wmse_change
;这里面保存了码块每个编码过程中对斜率的贡献。如果使第一个
block
的第一个编码过程,那么采用
-1
的估计失真长度曲线斜率;否则采用一个斜率的对数值。
1.
首先将
wmse
分成
2
的
32
次方等份,这个作为每个过程的
pass_wmse_scale
。这里分成这些等份的原因在于编码的时候使用的
32bit
的整数;当然最高位为符号位。每个编码过程的
wmse
的
scale
都不一样,当前过程的
pass_wmse_scale
是上个过程的四分之一。由于位平面编码并非从第
30
位开始,所以对于丢弃的
msb
,需要乘以指定数个
1/4
。
注,这里不知道为什么要乘
1/4
。
2.
进行一次过程编码后,根据当前过程的信息查表计算得到该过程对整个图像失真的改变值
distortion_change
。这个值于当前过程的
pass_wmse_scale
的乘积作为当前过程的
wmse
改进值存放到每个过程对应的
pass_wmse_change
数组中。
3.
如果不是第一个
block
的第一个编码过程;那么预测的斜率门限值应该是大于
0
,那么检查并判断当前过程是否已经满足该斜率值了。基本按照如下方式计算:
a)
每个过程由一个编码长度值
pass_lengths
和
wmse
的改进值:
pass_wmse_changes
;第一个作为长度的改进量,第二个作为失真的改进量。
b)
如果斜率与上面长度改进量的乘积比失真改进量大,说明这个过程以后的斜率都要比预测的斜率值小了;那么这个时候可以停止该
block
的编码过程了。
注,这一步实际上也算是比较耗时间的过程。
4.
完成需要的编码过程后,对应编码过程应该已经由了失真信息和长度信息。这个时候需要来检查上面编码过程中那些过程结束是优化的,同时找出每个编码过程对应的斜率。这里以实际编码的过程作为参数。
5.
开始的时候设置斜率位-
1
;然后累计第一个过程的长度和失真值(分别在
pass_lengths
和
pass_wmse_change
中),得到
D
和
L
的比值,这个作为当前过程的斜率;对于第二个过程需要累计第一个、第二个两个过程的值,得到一个斜率值;最终得到的值如果小于等于
0
;那么设置该过程的斜率为
0
;否则取上面值的对数作为当前过程的斜率值。
6.
完成上面操作后,再检查保留的过程中,按照编码顺序后面的过程斜率是否比前一个过程的斜率大,如果大保留后面那个过程的斜率,小的值修改为
0
。因此在完成
5
和
6
之后,被保存下来的点值都大于
0
,二其他被抛弃的点斜率变为
0
。
7.
在完成
block
编码后需要更新全局状态(其在
kd_compressed_stats
中。
8.
首先我们将当前
block
的大小,也就是多少个样本添加到被编码过程的样本数中(
num_coded_samples
),第一个
block
时,这个值时
0
。这里需要这个值作为
trim
的依据和下个
block
编码时使用的值。
9.
统计每个编码过程的斜率和长度值,并将斜率值量化为
1/16
作为数组
quant_slope_rates
(这是
1
个
4096
元素的数组,里面保存在该斜率下总共编码的长度,也就是说如果不同的
block
具有相同的斜率的过程长度值被累加到一起)入口;当然,如果那些斜率为
0
的点需要被跳过,其长度被累加到下个在曲线上的编码过程。同时更新一下当前可以使用的最大和最小斜率值。
10.
在
8
中提到的
num_coded_samples
用来检查是否需要考虑
trim
多于的数据。多余数据被
trim
的检查点为总体样本的:
2/16
、
3/16
、
4/16…
处,后面都是按照、
/16
增加。
11.
一旦需要
trim
的时候,首先按照总样本数量(注意这里不是已经编码的样本数量)和目标码率计算目标码流的长度,然后在
quant_slope_rates
中找到斜率,在这个斜率点所有
block
的所有过程长度的累加值比上面的总目标长度刚好大。而
trim
操作按照这个斜率值检查所有已经编码的
block
,
trim
掉所有比这个效率小的过程。可以看到在整个编码过程中,这样的
trim
操作最多需要进行
15
次,每次都一可能从所有块中将小于指定斜率的编码过程
trim
掉。上面的
trim
操作不会影响
quant_slope_rates
的值。
12.
上面已经完成了一个
block
的编码;下面开始第二个
block
的时候稍微与第一个有点不同;主要的不同在于现在
quant_slope_rates
中已经包含斜率长度值了。根据
num_coded_samples
(这里保守增加了额外长度)和目标码率计算期望的编码长度;然后从
quant_slope_rates
中发现到这个长度的斜率值,这个值作为当前
block
编码的最低的斜率门限。