DCT变换

灰度图测试

由于DCT只能对单通道数据进行,所以先介绍灰度图。

图像有RGB表示和**YCbCr(亮度、色度Chroma)**表示等。

利用matlab的rgb2gray函数可以将3通道彩色图转换为灰度图

得到图像灰度图还有另一种方式,就是用matlab的rgb2ycbcr函数转换为YCbCr颜色表示,然后单独将Y通道提取出来显示就是灰度图。

经过试验,得到的图像视觉上没有明显差异,但灰度图数值不同

%% 读取图像
clc;clear;close all;
img = imread("image\lena.png");
img_gray = rgb2gray(img);
img_ycbcr = rgb2ycbcr(img);
img_y = img_ycbcr(:,:,1);

%% 看是否灰度图和YCbCr的Y分量相不相同
subplot(1,2,1);
imshow(img_gray);
subplot(1,2,2);
imshow(img_ycbcr(:,:,1)); % 视觉效果没有明显差异,但是数值不一样

image-20240615135221579

image-20240615135318675

图像的高频与低频

图像不仅可以看做是像素点的组合,还可以从信号的角度来看,我们可以将图像的任意一行取出来绘制折线图:

%% 画256行的一个折线图
img_row = img_gray(256,:);
figure;
plot(img_row);

%% 在三维空间绘制像素变化情况
[height, width] = size(img_gray);
[X, Y] = meshgrid(1:width, 1:height);
Z = double(img_gray);
figure;
surf(X, Y, Z);
colormap('jet');
colorbar;
view(3);
axis equal;
grid on;
shading interp;
xlabel('X');
ylabel('Y');
zlabel('Pixel Value');
title('Image as a Smooth Surface');

image-20240615135701799

image-20240616143319742

image-20240615140720439

可以看到整个像素行有变化剧烈的部分以及变化平缓的部分。

实际上图像的低频信号就是像素变化平缓的部分,而像素的高频信号就是像素变化剧烈的部分,也常常有高频噪声的说法。而人眼对于高频细节信号不敏感的。对于低频信号较为敏感。

需要注意的一点是,现实世界中由相机拍摄的图像一般在像素间由较强的相关性,也就是一个小区域内的像素值一般比较接近,所以应该由大量低频信号组成,而高频信号只占一小部分

那么图像的高频低频,甚至于是不同频率的信号如何进行提取,这就需要用到DCT变换(Discrete Cosine Transform),通过DCT变换逆DCT变换,可以将一幅图像的像素值用不同频率余弦分量的线性组合表示。

DCT变换现象观察

理论上,DCT变换可以应用于任意长度的输入,但简单起见,只考虑8个样本点:

image-20240615143421253

考虑8个样本点 x 0 , x 1 , . . x 7 x_0,x_1,..x_7 x0,x1,..x7,经过DCT变换后得到一个等长的系数向量 X 0 , X 1 , . . . , X 7 X_0,X_1,...,X_7 X0,X1,...,X7,这就是离散余弦变换的目的:得到原始信号中由哪些余弦波组成,以及组成系数是多少。这里的 C 0 , C 1 , . . . C 7 C_0,C_1,...C_7 C0,C1,...C7就是不同频率的余弦波。

为了直观地看到当原始信号变化时,得到的DCT变换系数如何变化,我们不妨考虑输入一个标准余弦函数:

image-20240615143914754

由于余弦函数是连续的,要应用DCT,我们首先需要对其进行采样,也就是在 [ 0 , π ] [0,\pi] [0,π]内采样8个样本点,这里用如下的采样方法:将 [ 0 , π ] [0,\pi] [0,π]区间分成8等份,然后以每个子区间的中点位置为一个样本点(实际上这样采样和DCT变换中的余弦波保持 了一致):

image-20240615144444389

现在只考虑 N = 8 N=8 N=8的情况,其他情况可以类似地推广。

现在我们可以将采样得到的样本点向量输入DCT变换了,我们将观察到原始信号在以下三种情况下,DCT系数的变化情况:

  • 振幅变化
  • 上下平移
  • 频率变化
振幅变化
%% 振幅变化时 DCT的变化情况:DCT对应分量也变化,如果反向,DCT图像也会跟着反向
figure;
for k = [-1,1,2]
    for i = 0:7
        y(i+1) = k * cos((2*i+1)*pi / 16); %对标准余弦函数cos(x)进行采样,[0,π]采样8个点
    end
    y_dct = dct(y);
    plot(y_dct);
    hold on;
end
title("余弦函数振幅变化时,其DCT的变化情况")
legend("取负","振幅为1","振幅为2");

image-20240615144945435

可以看到,当振幅变化时,DCT系数对应的第2个分量 X 1 X_1 X1的值也发生了变化,而其他分量都是0

上下平移
%% 上下平移时,DCT的变化情况
figure;
for b = [-1,1]
    for i = 0:7
        y(i+1) = cos((2*i+1)*pi / 16) + b;
    end
    y_dct = dct(y);
    plot(y_dct);
    hold on;
end
title("余弦函数上下平移时,其DCT的变化情况")
legend("向下平移1","向上平移1");

image-20240615145415900

当原始余弦信号上下平移时,可以看到第二个DCT系数峰值依然存在并保持不变,而上下平移只改变了第一个DCT系数 X 0 X_0 X0的值(后面将得到第一个系数实际上直流分量,其他系数是交流分量),除前两个系数外,其他DCT系数都是0

频率变化
%% 频率变化时,DCT的变化情况
figure;
for k = 1:3
    for i = 0:7
        y(i+1) = cos((2*i+1)*pi*k / 16);
    end
    y_dct = dct(y);
    subplot(1,3,k);
    plot(y_dct);
    title(strcat("频率系数为", num2str(k)));
end
sgtitle("余弦函数频率变化时,DCT的变化情况");

image-20240615145808908

当原始余弦信号频率发生变化时,可以看到DCT系数峰值的位置也发生了变化,频率与其峰值的 x x x​索引一一对应的。可以以此类推,频率系数为4时,峰值对应的是 X 4 X_4 X4

我们发现频率系数1-7的的余弦波都有相对应的峰值索引,那剩余的频率系数为0的余弦波,由之前的上下平移变换可以得知,它对应的是索引为0的DCT系数。实际上频率为0的余弦波其实就是常值信号, c o s ( 0 ) = 1 cos(0)=1 cos(0)=1​。如果放到图像上来看,它其实就是一组图像的整体亮度,一组像素的整体亮度越高,那么它的索引为0的DCT系数就越大。反之越低。

实际上,每个频率都对应着一种图像模式,DCT所做的就是分解出各个基本模式,并计算它们对于原始图像的贡献

image-20240615151444438

下面我们将通过数学公式看到,8个像素值的所有可能组合都可以表示为这8个余弦波的总和

DCT数学原理

正变换

DCT系数的公式如下:

image-20240615152111184

我们可以发现公式中的余弦函数和最开始我们定义的余弦函数采样点相同,那么DCT各个分量系数实际上就表示为原始信号的采样点余弦波的样本点

为什么要做积呢,我们将公式换一种写法很容易就可以理解:

image-20240615152724223

实际上就是余弦信号采样点与原始信号向量做了点积,而我们知道点积是衡量向量相关性的一个重要方法。这就是为什么我们之前对频率系数为 k k k的余弦信号采样,做DCT变换后,其峰值 X k X_k Xk处,因为两个向量是完全相同的,所以其点积也是最大的。

更一般地,我们可以将DCT变换写成余弦分量矩阵原始信号向量乘积的形式:

image-20240615153903067

这个计算实质上就是一个简单的对原始信号的线性变换,但余弦信号分量矩阵具有重要的性质,那就是两两不同行相互正交,这也解释了为什么在前面的实验中,当我们向DCT输入一个特定频率的余弦信号时,只有一个峰值,而其他的系数都是0

逆变换

DCT变换的一个重要性质就是它是可逆的,由DCT系数我们可以无损地还原出原始信号。由正变换的矩阵形式,我们很容易就可以得出逆变换是怎样的:

image-20240615154419212

很重要的一点是,由于余弦分量矩阵不同行之间两两正交,所以它是一个近正交矩阵( A A T = k E AA^T=kE AAT=kE​),正交矩阵的逆就等于其转置,由于一个相同行相乘不一定等于1,所以在求逆时我们只需要用其转置再乘以一个归一化系数即可。

DCT逆变换实质上就是对余弦波进行线性组合,由于8个余弦波是两两正交的,就相当于一组基,所以任意8个原始信号采样都可以用这8个余弦波的线性组合表示。

实际应用

实际应用的时候,DCT变换采用如下公式:
X ( k ) = 2 / N ⋅ c ( u ) ⋅ ∑ n = 0 N − 1 x ( n ) c o s [ k ( 2 n + 1 ) π 2 N ] , k = 0 , 1 , . . . , N − 1 c ( u ) = { 1 2 u = 0 1 u > 0 X(k)=\sqrt{2/N}·c(u)·\sum_{n=0}^{N-1}x(n)cos[\frac {k(2n+1)\pi} {2N}],k=0,1,...,N-1 \\ c(u) = \begin{cases} \frac 1 {\sqrt{2}} \hspace{5mm}&u=0\\ 1 & u>0 \end{cases} X(k)=2/N c(u)n=0N1x(n)cos[2Nk(2n+1)π],k=0,1,...,N1c(u)={2 11u=0u>0
公式前部的 2 / N ⋅ c ( u ) \sqrt{2/N}·c(u) 2/N c(u)是归一化系数,保证了余弦分量矩阵是正交的。可以进行测试:

%% DCT归一化系数 N=8
y(1,1:8) = sqrt(1/8);
for i = 1:7
    for j = 0:7
        y(i+1,j+1) = sqrt(2/8) * cos((2*j+1)*pi*i / 16);
    end
end
s = y*y'; %s=单位矩阵E

image-20240615172800948

这里再介绍一个matlab中dctmtx的函数,该函数就是求DCT变换中归一化余弦分量矩阵的函数:

%% dctmtx函数测试
y(1,1:8) = sqrt(1/8);
for i = 1:7
    for j = 0:7
        y(i+1,j+1) = sqrt(2/8) * cos((2*j+1)*pi*i / 16);
    end
end
c = dctmtx(8); % 传入参数是N,即采样点数量

image-20240615174905652

可以看到用dctmtx函数计算出的余弦分量矩阵与我们手动计算的完全相同。

二维DCT变换

前面介绍的一维DCT变换,那要应用于图像需要二维DCT变换,变换过程就是先对图像的每一行进行一维DCT变换得到一个DCT系数矩阵,再将这个DCT系数矩阵的每一列进行一维的DCT变换得到最终的二维DCT变换系数。(DCT变换的可分离性:也可以先列后行,经过数学证明结果是一样的)

image-20240615155445969

DCT变换还具有能量集中的性质,意思是DCT系数矩阵左上角的DCT系数通常较大,这是因为一般图像中大部分都是低频信号,高频信号(右下)只占一小部分,这也是为什么在JPEG压缩中,右下角都可以量化成0的原因,图像由一些低频信号就已经能够构建出大致的模样,这也是人眼最敏感的。

数学公式

img

由于DCT变换具有可分离的性质,所以可以将二维DCT拆分成两个方向的一维DCT:

img

写成矩阵形式就是:

image-20240615173821603

image-20240615183710773

image-20240615183759855

由于矩阵乘法具有结合律,所以 Y = ( C X ) C T = C ( X C T ) Y=(CX)C^T=C(XC^T) Y=(CX)CT=C(XCT),表明无论是先对行做DCT再对列做DCT还是先对列做DCT再对行做DCT结果都一样。

基图像

上面公式中的 B i , j B_{i,j} Bi,j即为基图像, B i , j = β i β j T B_{i,j}=\beta_i \beta_j^T Bi,j=βiβjT,维度是 N × N N×N N×N,共 N × N N×N N×N​种频率的基图像,使用基图像求DCT系数进行两次一维DCT变换求DCT系数等价。

利用基图像进行2D DCT就是把对应频率的基图像和原始图像信号做逐像素乘积再对矩阵整体进行求和即可得到相应频率的DCT系数。

%% 二维DCT基图像
A = dctmtx(8);
B = A';
C = zeros(8, 8, 64);
m = 0;
for i = 1:8
    for j = 1:8
        m = m+1;
        C(:, :, m) = B(:, i)*A(j, :);
    end
end
minvalue = min(min(min(C)));
maxvalue = max(max(max(C)));
figure,
for k = 1:64
    subplot(8, 8, k)
    imshow(C(:, :, k), [minvalue, maxvalue]);
end

image-20240615183011355

DCT在图像变换时的性质(可用于设计抗相似性变换的水印)

索引从0开始,有以下性质:

image-20241105201711443

参考链接

[1] https://ww2.mathworks.cn/help/images/discrete-cosine-transform.html

[2] https://www.bilibili.com/video/BV1bc411q7YG/?spm_id_from=333.337.search-card.all.click&vd_source=bac8ddf04ec0b6386d58110f67353bc7

[3] https://blog.csdn.net/BigDream123/article/details/101426393

[4] https://blog.csdn.net/m0_51143578/article/details/129344131

[5] Guan H, Zeng Z, Liu J, et al. A novel robust digital image watermarking algorithm based on two-level DCT[C]//2014 International Conference on Information Science, Electronics and Electrical Engineering. IEEE, 2014, 3: 1804-1809.

<think>嗯,用户想了解离散余弦变换DCT)的原理和实现方法。首先,我需要回忆一下DCT的基本概念。DCT是一种将信号从时域转换到频域的技术,类似于傅里叶变换,但只使用余弦函数,所以对实数信号处理更高效。这在图像压缩中应用广泛,比如JPEG。 接下来,我应该先解释DCT的数学原理。根据引用[1],DCT有几种类型,其中DCT-II最常用。数学表达式是关键,用户可能需要公式来理解变换过程。所以需要写出DCT-II的一维和二维公式,用$$...$$格式。记得检查LaTeX语法是否正确,比如下标和求和符号。 然后是DCT的实现步骤。用户可能需要知道如何将理论应用到实际,比如预处理、分块、变换和量化。预处理部分,引用[2]提到数据预处理的重要性,需要减去像素值的平均值,这样DCT效果更好。分块处理通常是将图像分成8x8的块,这一步对于压缩很关键。 接着是代码实现部分。用户可能需要一个示例来理解如何编程实现DCT。这里应该用Python,使用numpy库进行矩阵运算。要注意二维DCT可以通过两次一维变换实现,代码要简洁明了,并且加上注释说明每一步的作用。 在应用部分,需要提到DCT图像压缩中的具体应用,比如JPEG,以及PSNR作为质量评估指标,引用[3]中的内容可以支持这一点。同时,可以提到量化的步骤,这是压缩的关键,但具体量化表的细节可能需要进一步解释。 最后生成相关问题,要围绕DCT的原理、实现步骤、应用和优化展开。比如数学推导、分块原因、与DFT的区别、量化影响等,这些问题能帮助用户深入理解。 检查是否所有数学公式都正确使用了$...$或$$...$$,比如变量x、n、k是否斜体,积分和求和符号是否正确。确保引用标记正确,比如引用[1]、[2]、[3]的位置是否合适,是否在回答末尾自然添加。另外,确保用中文回答,结构清晰,分步骤说明,代码示例正确。</think>### 离散余弦变换DCT)原理与实现方法 离散余弦变换DCT)是一种将信号从时域转换到频域的核心技术,特别适用于实数信号的高效处理[^1]。以下是其原理和实现方法的逐步说明: --- #### **一、DCT的数学原理** DCT的核心是通过余弦基函数分解信号,常用**DCT-II**(二维DCT)定义如下: - **一维DCT**: $$X_k = c_k \sum_{n=0}^{N-1} x_n \cos\left( \frac{\pi}{N} \left(n + \frac{1}{2}\right)k \right), \quad c_k = \begin{cases} \sqrt{\frac{1}{N}}, & k=0 \\ \sqrt{\frac{2}{N}}, & k \neq 0 \end{cases}$$ - **二维DCT**(图像处理常用): $$X_{u,v} = c_u c_v \sum_{i=0}^{N-1} \sum_{j=0}^{N-1} x_{i,j} \cos\left( \frac{\pi}{N} \left(i + \frac{1}{2}\right)u \right) \cos\left( \frac{\pi}{N} \left(j + \frac{1}{2}\right)v \right)$$ 其中$c_u, c_v$的取值与一维情况类似。 --- #### **二、DCT的实现步骤** 1. **预处理** 将图像像素值范围从$[0, 255]$调整为$[-128, 127]$(减去128),以提升频域能量集中性[^2]。 2. **分块处理** 将图像划分为$8 \times 8$的小块。例如,对$512 \times 512$的图像,得到$64 \times 64$个块。 3. **DCT变换** 对每个块应用二维DCT,将空域信号转换为频域系数。低频分量集中在左上角,高频分量在右下角。 4. **量化与压缩** 使用量化表对高频分量进行舍弃,保留主要低频信息(如JPEG压缩中的量化步骤)[^3]。 --- #### **三、Python代码示例** ```python import numpy as np def dct_2d(block): """二维DCT变换""" N = block.shape[0] dct_matrix = np.zeros((N, N)) # 构造DCT基函数 for u in range(N): for v in range(N): cu = np.sqrt(1/N) if u == 0 else np.sqrt(2/N) cv = np.sqrt(1/N) if v == 0 else np.sqrt(2/N) for i in range(N): for j in range(N): dct_matrix[u, v] += block[i, j] * np.cos((2*i+1)*u*np.pi/(2*N)) * np.cos((2*j+1)*v*np.pi/(2*N)) dct_matrix[u, v] *= cu * cv return dct_matrix # 示例:8x8块处理 block = np.random.randint(0, 256, (8, 8)) - 128 # 预处理 dct_result = dct_2d(block) ``` --- #### **四、DCT的应用** 1. **图像压缩**:JPEG标准中通过DCT+量化实现高压缩比[^3]。 2. **音频编码**:MP3等格式利用DCT提取频域特征。 3. **信号去噪**:保留低频分量,滤除高频噪声。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值