### [你的照片其实是一道数学题——图片压缩背后的数学原理](https://www.thinkhow.tech/article/582) **Published:** 2026-07-23T15:21:05 **Author:** 段, 誉 **Excerpt:** 用高中数学看懂JPG和PNG的数学本质:DCT把[100,200]变成[212,-71]再量化成[150,150];LZ77用(3,3)指针替代重复的”abc”;霍夫曼编码5种符号182位代替264位。从此再也不会存错图、用错格式。 ## JPG压缩:删掉你看不见的细节 ![](https://thinkhow.tech/wp-content/uploads/2026/07/%E5%9B%BE%E5%83%8F%E5%8E%8B%E7%BC%A9-1024x450.jpeg) DCT原理 → 概念展开 JPG的核心技术叫作**离散余弦变换(DCT)**。它先把一张图切成很多个8×8的小方块,然后对每个方块做二维DCT变换。完整的公式长这样: \\(F(u,v) = \\frac{1}{4} C(u)C(v) \\sum\_{x=0}^{7} \\sum\_{y=0}^{7} f(x,y) \\cos\\frac{(2x+1)u\\pi}{16} \\cos\\frac{(2y+1)v\\pi}{16}\\) 看起来有点复杂,但它的核心思想可以用一个简单的例子讲清楚。我们用一维DCT来理解,把两个相邻像素的亮度值看作一个N=2的序列: 输入 f = \[100, 200\]。一维DCT公式简化为: $$F(u) = C(u) \\sum\_{x=0}^{1} f(x) \\cos\\left\[\\frac{\\pi u (2x+1)}{4}\\right\]$$ 其中 u=0 时$$C(0)=\\sqrt(1/2)≈0.7071$$ ,u=1 时 C(1)=1。 **先算F(0)——直流系数(DC),代表「平均亮度」:** $$F(0) = 0.7071 \\times (100\\cos 0 + 200\\cos 0) = 0.7071 \\times 300 \\approx 212$$ **再算F(1)——交流系数(AC),代表「明暗差异」:** $$F(1) = 1 \\times \\left\[100\\cos\\frac{\\pi}{4} + 200\\cos\\frac{3\\pi}{4}\\right\]$$ 查表:$$\\cos\\frac{\\pi}{4} = \\frac{\\sqrt{2}}{2} \\approx 0.7071, \\quad \\cos\\frac{3\\pi}{4} = -\\frac{\\sqrt{2}}{2} \\approx -0.7071$$ $$F(1) = 100 \\times 0.7071 + 200 \\times (-0.7071) = 70.71 – 141.42 \\approx -71$$ 所以两个像素 \[100, 200\] 经过DCT后变成了两个系数 \[212, -71\]。其中212代表整体的亮度水平(平均亮度×√2),-71代表两个像素之间的差异——这就是把「空间信息」转换成了「频率信息」。 量化与有损 → 对比深化 接下来是量化的步骤。人的眼睛对低频(大面积明暗)很敏感,但对高频(细微差异)很迟钝。所以JPG把高频系数除以一个较大的数字再取整,许多高频系数就这样变成了零。 在我们的例子里,假设我们把F(1)设为0(丢弃差异信息),只保留F(0)=212。然后做逆变换看看结果: $$f'(0) = 0.7071 \\times 212 \\times \\cos 0 + 1 \\times 0 \\times \\cos\\frac{\\pi}{4} = 150$$ $$f'(1) = 0.7071 \\times 212 \\times \\cos 0 + 1 \\times 0 \\times \\cos\\frac{3\\pi}{4} = 150$$ 原来 \[100, 200\] 两个差异明显的数值,量化后逆变换回来变成了 \[150, 150\]——两个值都变成了平均值。这就是「有损压缩」的数学本质:丢弃高频分量来省空间,代价是两个原本不同的像素变得一模一样了。 扩展到真实场景:8×8的方块经过2D DCT后得到64个系数,左上角的F(0,0)叫DC系数(平均亮度),越往右下角频率越高。JPEG对高频系数(右下角)用大的量化数值去除,让它们变成零;对低频系数(左上角)用小的量化值,尽量保留。量化程度越高,零越多,文件越小,画质损失也越大——这就是为什么反复保存JPG会越来越糊。 霍夫曼编码 → 例证展开 量化之后,剩下的非零系数经过Z字形扫描重新排列,再交给**霍夫曼编码**进一步压缩。霍夫曼编码的核心思想是:给出现频率高的符号分配短编码,给频率低的分配长编码。 举一个简单的例子。假设某张图量化后的系数中,「0」出现了50次,「1」出现了20次,「2」出现了10次,「3」出现了5次,「4」出现了3次。霍夫曼编码会这样建树排序: | 符号 | 出现次数 | 编码 | 位数 | | --- | --- | --- | --- | | 0 | 50次 | **0** | 1位 | | 1 | 20次 | **10** | 2位 | | 2 | 10次 | **110** | 3位 | | 3 | 5次 | **1110** | 4位 | | 4 | 3次 | **1111** | 4位 | 总共88个符号,等长编码(3位)需要264位,霍夫曼编码只需要50×1+20×2+10×3+5×4+3×4=182位,省了31%。 ## PNG压缩:不丢一个像素的数学魔术 LZ77算法 → 概念展开 PNG走的是完全不同的路:**无损压缩**。它的核心技术叫**DEFLATE算法**,由两个阶段组成。第一阶段:**LZ77算法**——「找重复」。用一个滑动窗口扫描数据,发现当前数据在过去32KB内已经出现过时,就记录一个指针(距离,长度),而不是重复存储相同的字节。 输入字符串:`abcabcabc`(9个字符)。逐位扫描过程如下: | 位置 | 当前字符 | 是否出现过? | 输出 | | --- | --- | --- | --- | | 0 | a | 未出现 → 输出原文 | **a** | | 1 | b | 未出现 → 输出原文 | **b** | | 2 | c | 未出现 → 输出原文 | **c** | | 3 | a | 在位置0出现过。找最长匹配:abc在位置0-2出现过 ✓ | **(3, 3)** | | 6 | a | 在位置0出现过。找最长匹配:abc在位置0-2出现过 ✓ | **(6, 3)** | 结果:`a b c (3,3) (6,3)`,从9个字符压缩到5个token。解压时,(3,3)的意思是「回到前面第3个位置,复制3个字符过来」,完全可以还原成「abcabcabc」。这就是无损压缩的精髓——不删任何信息,只换一种更紧凑的存储方式。 预过滤 → 概念界定 第二阶段是**霍夫曼编码**,对LZ77输出的字符和指针再做一次编码压缩,原理和JPG中的霍夫曼编码相同。不过图片的像素数据通常不是整齐排列的重复序列。为了提高LZ77找重复的效率,PNG在压缩之前还做了**预过滤**。 它把原始像素值变成与相邻像素的差值:如果相邻像素颜色相近,差值趋近于零,数据中出现大量重复的零,LZ77的压缩效率一下子就上来了。这就是为什么PNG对文字截图和纯色LOGO压缩效果极好(相邻像素几乎一样,差值全是零),而对复杂的自然照片效果远不如JPG。 ## 三种格式的本质对比 格式对比 → 归纳升华 JPG之所以超小,是因为它通过DCT把人眼不敏感的高频信息直接丢弃——这是数学层面的「取舍策略」。PNG之所以大,是因为它通过DEFLATE不丢任何信息地压缩——这是数学层面的「无损压缩天花板」。截图存PNG更清晰,是因为文字和图标的锐利边缘在JPG的DCT量化中会被模糊,而PNG能精确保留每一个像素的位置和颜色。拍照必须用JPG,则是因为自然照片几乎没有完美的重复模式,PNG的压缩率远不如JPG——在不牺牲视觉质量的前提下,JPG可以做到十倍以上的压缩比。 至于RAW格式,它连「代码」都不是——它是相机传感器捕捉到的原始电信号数据,未经任何数学变换和色彩处理,相当于食材而非菜肴。它的体积最大,但后期调整的空间也最大。 数学方案 → 号召收束 每种格式都是一套数学方案:JPG选择「视觉上差不多就行」,PNG坚持「一个像素都不能少」,而RAW说「我还没开始做菜」。理解了它们背后的数学原理,你就再也不会存错图、用错格式了。 **Tags:** 交互, 知识, 高级 **Categories:** 学科, 数学 ---