离散余弦变换(DCT)详解
离散余弦变换DCT详解离散余弦变换Discrete Cosine Transform, DCT是视频和图像编码中最重要的数学工具之一。它是 JPEG、H.264、H.265 (HEVC) 等标准的核心组件。简单来说DCT 的作用是将图像从“空间域”转换到“频率域”从而把能量集中起来方便压缩。一、为什么要用 DCT1. 空间域 vs 频率域空间域Spatial Domain我们看到的像素矩阵。每个值代表某个位置的亮度或颜色。特点数据之间相关性高难以直接压缩。频率域Frequency Domain描述图像变化快慢的系数矩阵。低频系数代表图像的平坦区域、大致轮廓能量集中处。高频系数代表图像的边缘、细节、噪声能量分散且人眼不敏感。2. DCT 的核心价值能量集中Energy Compaction自然图像通常具有空间相关性相邻像素的值往往很接近。DCT 可以将这种相关性转化为大部分能量集中在左上角的少数几个低频系数上而右下角的高频系数接近于 0。原始残差块 (空间域) DCT 变换后 (频率域) [ 10] [ 12] [ 11] [ 10] [ 45] [ -2] [ 1] [ 0] [ 11] [ 13] [ 12] [ 11] [ -3] [ 1] [ 0] [ 0] [ 10] [ 11] [ 10] [ 9] [ 2] [ 0] [ 0] [ 0] [ 9] [ 10] [ 9] [ 8] [ 0] [ 0] [ 0] [ 0] 注意 1. 左上角 (DC系数) 很大代表平均值。 2. 右下角大量变为 0 或极小值。 3. 量化时右下角的 0 可以被高效压缩行程编码/熵编码。二、DCT 的数学原理1. 一维 DCT 公式对于长度为NNN的序列x[n]x[n]x[n]其 DCT 变换X[k]X[k]X[k]为X[k]α(k)∑n0N−1x[n]cos[πN(n12)k] X[k] \alpha(k) \sum_{n0}^{N-1} x[n] \cos\left[ \frac{\pi}{N} \left(n \frac{1}{2}\right) k \right]X[k]α(k)n0∑N−1x[n]cos[Nπ(n21)k]其中k0,1,...,N−1k 0, 1, ..., N-1k0,1,...,N−1α(0)1/N\alpha(0) \sqrt{1/N}α(0)1/N,α(k)2/N\alpha(k) \sqrt{2/N}α(k)2/N(k0k 0k0)2. 二维 DCT 公式图像常用对于N×NN \times NN×N的图像块f(x,y)f(x,y)f(x,y)F(u,v)α(u)α(v)∑x0N−1∑y0N−1f(x,y)cos[πN(x12)u]cos[πN(y12)v] F(u,v) \alpha(u)\alpha(v) \sum_{x0}^{N-1} \sum_{y0}^{N-1} f(x,y) \cos\left[ \frac{\pi}{N} \left(x \frac{1}{2}\right) u \right] \cos\left[ \frac{\pi}{N} \left(y \frac{1}{2}\right) v \right]F(u,v)α(u)α(v)x0∑N−1y0∑N−1f(x,y)cos[Nπ(x21)u]cos[Nπ(y21)v]F(0,0)F(0,0)F(0,0)称为DC 系数直流分量代表块的平均亮度。其他F(u,v)F(u,v)F(u,v)称为AC 系数交流分量代表不同频率的细节。3. 逆变换IDCT解码器使用 IDCT 将频率系数还原为像素值。由于 DCT 是正交变换IDCT 公式与 DCT 非常相似只是余弦项的位置互换。三、在 H.265/HEVC 中的应用1. 变换单元TU在 HEVC 中DCT 作用于变换单元Transform Unit, TU。TU 的大小可以是4×4,8×8,16×16,32×324\times4, 8\times8, 16\times16, 32\times324×4,8×8,16×16,32×32。对于4×44\times44×4的帧内预测残差HEVC 还引入了DST离散正弦变换因为它对边缘信号的压缩效率略高于 DCT。2. 编码流程中的位置原始像素 - 预测像素 残差 (空间域) ↓ DCT 变换 ↓ 变换系数 (频率域) ↓ 量化 (Quantization) -- 有损压缩发生在这里 ↓ 熵编码 (CABAC)3. 整数 DCTInteger DCT问题标准的 DCT 涉及浮点运算cosine在不同硬件上会有精度误差导致编码器和解码器重建出的图像不一致。解决H.265 标准定义了整数近似 DCT。使用整数乘法和移位代替浮点运算。保证编解码端的完全匹配Match。虽然引入了微小的舍入误差但压缩效率几乎不受影响。四、X265 中的 DCT 实现在 X265 源码中DCT 的实现位于source/common/dct.cpp和source/common/x86/dct.asm。1. 核心函数结构// source/common/dct.hstructTComTrCore{// 正向变换voidtransformNxN(coeff_t*coeff,constpixel_t*residual,intwidth,intheight);// 反向变换voidinvTransformNxN(pixel_t*reconstruction,constcoeff_t*coeff,intwidth,intheight);// 具体的尺寸实现voiddct2_4x4(constpixel_t*src,coeff_t*dst,intptr_t srcStride);voiddct2_8x8(constpixel_t*src,coeff_t*dst,intptr_t srcStride);voiddct2_16x16(constpixel_t*src,coeff_t*dst,intptr_t srcStride);voiddct2_32x32(constpixel_t*src,coeff_t*dst,intptr_t srcStride);};2. 快速算法Fast DCT直接计算 DCT 需要O(N2)O(N^2)O(N2)次运算。X265 使用类似 FFT 的快速分解算法将大矩阵分解为小矩阵复杂度降至O(NlogN)O(N \log N)O(NlogN)。例如8×88\times88×8DCT 可以分解为多个4×44\times44×4和2×22\times22×2的步骤利用对称性减少乘法次数。3. SIMD 优化DCT 是计算密集型任务X265 heavily 依赖 SIMD 指令集加速SSE2/AVX2并行处理多个像素点的乘加运算。汇编实现在dct.asm中手写汇编精确控制寄存器分配达到极致性能。; source/common/x86/dct.asm (简化示例) cglobal dct2_8x8, 3,4 ; 加载 8x8 像素块到 SIMD 寄存器 movu xmm0, [src] movu xmm1, [srcstride] ... ; 执行蝶形运算 (Butterfly Operations) paddw xmm0, xmm1 psubw xmm2, xmm3 ... ; 乘以变换矩阵常数 pmulhw xmm0, [coeff_table] ... ; 存储结果 movu [dst], xmm0 ret五、DCT 系数的分布特征经过 DCT 变换后系数分布呈现明显的非均匀性DC 系数通常最大包含块的主要能量。低频 AC 系数数值较小但通常非零。高频 AC 系数绝大多数接近 0。这种分布对后续步骤至关重要量化可以对高频系数使用更大的量化步长将它们直接变成 0。扫描Scanning使用 Zig-Zag 扫描或水平/垂直扫描将非零系数聚在一起便于行程编码Run-Length Coding。六、常见问题与误区1. DCT 是有损的吗不是。DCT 本身是一个可逆的数学变换只要精度足够。有损发生在量化阶段。量化器根据 DCT 系数的视觉重要性丢弃或粗略表示高频系数。2. 为什么不用 FFT傅里叶变换实数运算DCT 只产生实数系数而 FFT 产生复数。处理实数更简单、存储更省。边界效应DCT 隐含了信号偶对称扩展比 FFT 的周期延拓在块边界处产生的伪影更少。能量集中能力对于高度相关的图像信号DCT 的能量集中性能优于 FFT。3. 块效应Blocking Artifacts的来源DCT 是基于块进行的如8×88\times88×8或16×1616\times1616×16。如果量化太粗块与块之间的边界会出现不连续形成“格子状”伪影。这就是为什么需要去块滤波Deblocking Filter。七、总结DCT 在视频编码中的地位✅桥梁连接空间域像素和频率域系数。✅去相关消除像素间的空间冗余。✅能量集中为量化提供便利让编码器知道哪些信息重要哪些可以丢弃。在 X265 中DCT 的实现经过了极致的优化整数化、快速算法、SIMD 加速以确保在保持高压缩效率的同时尽可能降低编码器的计算耗时。它是现代视频压缩技术的基石之一。