🎬 第六章 音视频压缩编码基础
📄 一句话概括

熵编码是整条链路里的无损收尾:不丢信息,只把常出现的符号换成短码——它决定的是【表示效率】。

📝 本节和前面几节的关系

6.3.3 讲了量化,这一节讲最后一步:把符号按概率压一压。

一、熵编码在做什么

经过前面的步骤,数据已经变成一串符号(系数、模式号、运动矢量)。 这些符号的出现概率并不均匀——有的频繁出现,有的一辈子见不到几次。 熵编码做的事就是:高频符号给短码,低频符号给长码。 关键在于:它完全无损,一个比特都不丢。

二、一个算例

四个符号,出现次数分别是 50、25、15、10 次: 定长码:每个都 2 位,一共 200 位; 霍夫曼码:按频率分配成 1、2、3、3 位,一共 175 位; 省下 12.5%——看起来不多,但这是在已经压过几十倍之后又省的。 所以熵编码是【最后一道无损的收尾】。

三、两种常见实现

霍夫曼编码:给每个符号一张固定码表——实现简单、速度快。 算术编码/CABAC:把整串符号映射成一个小数——效率更高但更慢。 现代视频编码(H.264/H.265)默认用后者,因为压缩率的收益很大。 代价是复杂度——这也是【H.265 编码慢】的原因之一。

四、它为什么能保证无损

因为它做的是一一映射:每个符号都有确定的码字,码字之间不会混淆。 只要码表确定、解析规则确定,就能一分不差地还原回来。 这一点非常重要:如果连熵编码都有损,那前面几步就白算了。 所以整条压缩链条的分工是:前面负责【丢得聪明】,它负责【装得紧凑】。

五、动手 Demo:熵编码把符号换成短码

熵编码是无损的:它只是【把常出现的符号换成短码】。

rows = [("A", "50", "1 bit"), ("B", "25", "2 bit"),
        ("C", "15", "3 bit"), ("D", "10", "3 bit")]
for a, b, c in rows:
    print("%-4s %-12s %s" % (a, b, c))
total = 50 * 1 + 25 * 2 + 15 * 3 + 10 * 3
print("定长 200 位 vs 霍夫曼 %d 位 -> 省下 %.1f%%" % (total, (1 - total / 200.0) * 100))

实跑输出:

--------------------------------------------------------------------
熵编码把符号换成短码
--------------------------------------------------------------------

熵编码是无损的:它只是【把常出现的符号换成短码】。

  符号     出现次数     霍夫曼码长
  ---------------------------------
  A        50           1 bit
  B        25           2 bit
  C        15           3 bit
  D        10           3 bit

  定长码要 200 位,霍夫曼码只要 175 位——**省下 12.5%。**
  这就是熵编码的全部本事:**不丢信息,只换表示。**

定长码要 200 位,霍夫曼码只要 175 位——省下 12.5%。 这就是熵编码的全部本事:不丢信息,只换表示。

30 秒实验

  1. 统计一段文字里各字母的出现次数,试着给它排一套短码。
  2. 算一下比定长码省了多少。

常见误区

  1. 以为熵编码也丢信息。它是整条链路里唯一的无损环节之一。
  2. 以为熵编码省得少就不重要。它是在几十倍压缩之上再省的。
自测三问(点开对答案) 1. 熵编码的依据是什么? —— 符号出现的概率差异——高频符号用短码。 2. 霍夫曼编码与算术编码有什么区别? —— 前者用固定码表、快;后者效率更高但更慢。 3. 为什么熵编码能保证无损? —— 它做的是一一映射,码字与解析规则确定,可以精确还原。

相关笔记