The discrete cosine transform (DCT) writes a sequence of samples as a weighted sum of cosines of increasing frequency.
Properties
- The coefficients are real
- The transform is orthonormal
- Energy of smooth signals concentrates in the first few coefficients
- The inverse transform reconstructs the samples exactly, up to rounding
One-Dimensional DCT
For samples , :
Here:
- : frequency index
- :
- for :
- : DC coefficient, equal to times the sample mean
- for : AC coefficients
The term completes cycles across the samples.
Two-Dimensional DCT
For an block with the column and the row:
Here:
- : horizontal and vertical frequency indices
- : DC coefficient, equal to times the block mean
- for : AC coefficients
For , with and otherwise. The 2D transform then has the form
A constant block of value gives and all AC coefficients 0.
Matrix Form
The kernel is separable, so the 2D transform is a 1D transform on every row followed by a 1D transform on every column.
- is stored with the row index first, so
- is stored with the vertical frequency first, so
- is orthogonal, so
- depends only on and is computed once
Basis Functions
The inverse DCT writes each block as a weighted sum of fixed patterns:
- is constant
- completes cycles horizontally and cycles vertically across the block
- Frequency grows from the top-left to the bottom-right of
Because is orthogonal, the patterns are orthonormal and the transform preserves energy.
Squared error in the coefficient domain therefore equals squared error in the sample domain.
Choice of Transform
- Compaction
For highly correlated neighbouring samples, the DCT approaches the Karhunen–Loève transform in energy compaction, without needing signal-dependent basis vectors. - Boundary behaviour
The DCT is the DFT of an even-symmetric extension of the block. The extension has no jump at the block border, so it avoids the leakage that the DFT produces from wrap-around discontinuities. - Real arithmetic
All coefficients are real. The DFT of a real block is complex.
Fast Computation
- Direct evaluation of the 2D sum costs multiplications per block, which is 4096 for
- Row-column evaluation costs multiplications, which is 1024 for
- Fast 1D factorisations cost per transform. The AAN algorithm needs 5 multiplications for , since it leaves out the scale factors and expects the caller to fold them in later, for example into the divisors of a quantizer
Implementation
Row-column evaluation with a precomputed matrix:
from math import cos, pi, sqrt
def dct_matrix(N):
T = [[0.0] * N for _ in range(N)]
for k in range(N):
a = sqrt(1 / N) if k == 0 else sqrt(2 / N)
for n in range(N):
T[k][n] = a * cos((2 * n + 1) * k * pi / (2 * N))
return T
def matmul(A, B):
return [[sum(A[i][k] * B[k][j] for k in range(len(B))) for j in range(len(B[0]))]
for i in range(len(A))]
def transpose(A):
return [list(row) for row in zip(*A)]
def dct2(f, T): # F = T f T^t, f[y][x] -> F[v][u]
return matmul(matmul(T, f), transpose(T))
def idct2(F, T): # f = T^t F T
return matmul(matmul(transpose(T), F), T)
Checks for a correct implementation:
- A block of all 5s with gives and every other coefficient 0
idct2(dct2(f, T), T)returnsfup to floating point error- The sum of squares of
fequals the sum of squares ofdct2(f, T)