把一张1920×1080的彩色照片原样存下来,需要多少空间?不压缩的RGB数据是1920×1080×3字节,算下来大概6.2MB。一部64GB的手机,刨去系统和App占用的空间,也就放得下一万张左右。可我们平时手机拍的照片,存储时大多只有2MB到5MB,放大看却几乎看不出差别。中间被"省掉"的那几个MB,正是图像压缩编码在起作用。
这是"信号处理仿真:图像信号处理"系列的第6篇。前几篇我们分别聊过图像的采样、量化、增强、复原这些环节,目标都是让信号更清晰、更完整。到了压缩编码这一步,任务反过来了:不是让数据变得更多,而是在尽量不损失视觉质量的前提下,把数据量狠狠压下去。这篇文章我用仿真实验的视角,把图像压缩编码这条技术路线从原理、实现到评价完整走一遍,代码以Python为主,MATLAB思路完全一致。适合正在学数字图像处理、信号处理仿真,或者想真正搞懂JPEG背后机制的人。
1. 一张图为什么这么占空间:三种冗余先说清楚
先搞清楚一个问题:一幅图像数据里,哪些内容是可以被省掉的?把这个问题想明白了,后面所有算法都是顺理成章的事。我把图像数据里能压缩的部分归纳成三类冗余,这三类冗余对应着三种不同的压缩手段。
1.1 空间冗余:相邻像素太"像"了
拍照时,一块纯净的天空、一面白墙、一片草地,在图像上表现为大范围的、颜色非常接近的像素。最极端的例子是纯色图像,比如一幅256×256、每个像素都是RGB(128,128,128)的图,理论上用三个字节就能完整描述出来,但BMP格式会老老实实存下196608个字节。这就是典型的空间冗余——像素与相邻像素之间有极强的相关性。
信号处理里经常说"去相关",就是把这种相邻像素高度相似的状态打破,让数据在统计上变得"独立"。DCT、小波变换这类正交变换,核心作用就是去相关。你可以这样理解:变换把图像从"像素值高度相关"的空间,搬到了一个"系数相对独立"的空间,再对系数做处理就方便多了。本质上,变换本身不压缩数据,它只是让后续的量化、编码更有效率。
1.2 视觉冗余:人眼本来就不敏感的部分
人眼对亮度比对颜色敏感,对低频信息比对高频细节敏感,对平滑区域里的微小噪声几乎无感。这是所有有损压缩技术的生理基础。JPEG在颜色空间转换后,把色度通道下采样到1/4分辨率;在量化阶段,把高频系数除以一个较大的数再取整。这两个操作都在利用视觉冗余:丢掉一些人类视觉系统感知不明显的信息,换取可观的码率下降。
视觉冗余最直观的例子是色度下采样。研究人员很早就发现,人眼对色彩细节的分辨能力远低于对亮度细节的分辨能力。把一个2×2像素块的颜色信息合并成一个值,人的眼睛几乎察觉不到,但色度数据量直接减少了75%。这种"骗过眼睛"的取舍,在压缩编码里无处不在。
1.3 编码冗余:等长编码不是最优解
即使像素值本身无法再省,存储环节依然有压缩空间。假设一幅灰度图里灰度值128出现得非常频繁,灰度值0几乎不出现,那给128分配一个短码字、给0分配一个长码字,平均每个像素的存储成本就能低于固定8bit。Huffman编码做的就是这件事:用变长编码给高频出现的值分配短码字,给低频出现的值分配长码字。
一个不涉及任何有损操作的理想Huffman编码,通常能压掉10%~30%的数据量。这意味着,即使我们不做任何视觉上的妥协,纯无损压缩也有不小的收益。后面讲到的JPEG流程里,Huffman编码是最后一道工序,它承接量化之后的数据,把符号流变成真正的比特流。
1.4 压缩率、bpp和比特率:先把口径统一
聊压缩之前,必须先把度量口径统一,不然很容易被数字误导。以一幅512×512的8bit灰度图为例:
- 原始大小 = 512 × 512 × 8 bits = 2097152 bits = 256KB
- 无损压缩后大约180~220KB,取决于图像内容
- JPEG质量因子80左右,通常能到30~60KB
- JPEG2000或更现代的标准,在相同质量下还能再小20%~40%
压缩率通常用"原始数据量 / 压缩后数据量"表示,256KB压到32KB,压缩率就是8:1,也叫8倍压缩。另一种常见口径是bpp(bit per pixel),即平均每个像素用多少bit编码,0.5bpp对8bit灰度图来说就是压缩到原来的1/16。还有场合用比特率,比如2Mbps,多用于视频。做图像仿真时,bpp和压缩率用得最多,记得在论文或博客里注明口径,不然别人复现时会对不上数。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. JPEG编码器内部的三件套:变换、量化、熵编码
JPEG标准1992年发布,到现在仍是使用最广泛的图像编码标准,没有之一。它之所以能"活"这么久,是因为框架非常干净:颜色空间转换、分块DCT、量化、熵编码。接下来我把每个模块逐个拆开,讲清楚为什么每一步都是必须的,以及它们之间是怎么衔接的。
2.1 为什么先做DCT而不是直接量化像素
有损压缩最核心的操作是量化。但如果在像素域直接做量化,把256个灰度级变成32个或16个,图像会立刻出现明显的色阶
