DCT变换,离散余弦变换,将时域/空间域转换到频域上。是DFT离散的傅里叶变换去掉虚数项的表示。常用于图像音频压缩技术上,如jpeg,h264,mpeg算法中。DCT变换后可以将高频的信号通过量化等方式去掉,以实现压缩,因为高频信号往往是人们不关注的,或者影响很小。
DCT变换就是限定了输入信号的DFT(离散傅里叶)变换,输入信号是实偶信号。
一维DCT变换:
推导与理解见知乎:
https://zhuanlan.zhihu.com/p/85299446
二维DCT变换:
二维DCT变换无非是一维多了一个分量而已,公式是相同的。
矩阵表示和matlab程序
DCT变换有高度的对称性,用矩阵表示:
matlib代码:
clear;
clc;
X=[
61 19 50 20
82 26 61 45
89 90 82 43
93 59 53 97] %原始的数据
A=zeros(4);
for i=0:3
for j=0:3
if i==0
a=sqrt(1/4);
else
a=sqrt(2/4);
end
A(i+1,j+1)=a*cos(pi*(j+0.5)*i/4); %生成变换矩阵
end
end
Y=A*X*A' %DCT变换后的矩阵
X1=A'*Y*A %DCT反变换恢复的矩阵
逆变换公式:
c代码:
#include <stdio.h>
#include <math.h>
#include <stdio.h>
/*
* params:
in: in_matrix, input matrix to transfer
line_num: line
row_num: row
out: out_dct
*/
void dct_transfer(float **out_dct, float **in_matrix, int line_num, int row_num)
{
float c_u = 0;
float c_v = 0;
for (int u = 0; u < line_num; u++)
{
for (int v = 0; v < row_num; v++)
{
out_dct[u][v] = 0;
// calc sum
for (int x = 0; x < line_num; x++)
{
for (int y = 0; y < row_num; y++)
{
out_dct[u][v] += in_matrix[x][y] *cos(M_PI/((float)line_num) *(x + 0.5)*u) * cos(M_PI/ ((float)row_num)* (y+0.5) *v);
}
}
c_u = (u==0? sqrt(1.0/line_num) : sqrt(2.0/line_num));
c_v = (u==0? sqrt(1.0/row_num) : sqrt(2.0/row_num));
out_dct[u][v] = c_u * c_v * out_dct[u][v];
}
}
}
void idct_transfer(float **out_matrix, float **in_dct, int line_num, int row_num)
{
float c_u = 0;
float c_v = 0;
for (int i = 0; i < line_num; i++)
{
for (int j = 0; j < row_num; j++)
{
out_matrix[i][j] = 0;
for (int u = 0; u < line_num; u++)
{
for (int v =0; v < row_num; v++)
{
c_u = (u==0? sqrt(1.0/line_num) : sqrt(2.0/line_num));
c_v = (u==0? sqrt(1.0/row_num) : sqrt(2.0/row_num));
out_matrix[i][j] += c_u * c_v* in_dct[u][v] * cos(M_PI/((float)line_num) *(x + 0.5)*u) * cos(M_PI/ ((float)row_num)* (y+0.5) *v)
}
}
}
}
}
分块DCT变换
在图像处理中,一张图的数据很大,需要将其分块处理,比如h264,就将图分为1616或88的宏块,然后再进行DCT变换,然后进行量话,Z型编码,熵编码等操作。随着子块变大,算法的复杂度会急剧上升。
https://www.cnblogs.com/wyuzl/p/7880124.html