一:离散余弦变换(Discrete Cosine Transform,DCT)
离散余弦变换(Discrete Cosine Transform,DCT):是一种数学变换,它将一连串的离散值,如数字图像或信号,转换为代表图像或信号的频率成分的系数序列。DCT被广泛用于图像和信号处理、数据压缩和数字通信中。DCT的主要优点之一是它提供了一个图像或信号在其主要频率成分方面的紧凑表示,使其有可能在不损失很多信息的情况下压缩数据。DCT类似于更知名的傅里叶变换,但更适合于处理现实世界中具有有限长度和非周期性的信号和图像。DCT被用于几种流行的图像和视频压缩格式,如JPEG和MPEG
(1)一维DCT
A:定义
一维DCT变换定义:一维DCT是一种数学变换,它为一个给定的输入序列计算一组频率系数,使用不同频率的余弦函数的加权和。由此产生的频率系数可用于分析和压缩输入序列,以及其他应用。定义式如下
- f(x)代表输入信号或序列,它由**N样本或数值**组成
- DCT用于将这个输入序列转换为一组N的频率系数F(u),其中u是频率系数的索引
- 求和里面的余弦函数是DCT的主要部分。它的参数由索引u和样本索引x组成,其参数由\frac{(2x+1)u\pi}{2N}给出。余弦函数用于提取输入序列的频率成分,而求和则用于计算每个样本对每个频率系数的贡献
- 因子\sqrt\frac{2}{N}是一个归一化常数,确保DCT是一个正交变换,也就是说,它保留了输入序列的能量。常数C(u)是另一个归一化常数,它取决于索引u和正在使用的DCT的变体。DCT的不同变体使用不同的归一化常数,这影响了变换的特性
F(u)=C(u) \sqrt{\frac{2}{N}} \sum_{x=0}^{N-1} f(x) \cos \frac{(2 x+1) u \pi}{2 N} \quad u=0,1, \cdots, N-1
一维IDCT变换定义:IDCT是DCT的逆变换,定义式如下
f(x)=\sqrt{\frac{2}{N}} \sum_{u=0}^{N-1} C(u) F(u) \cos \frac{(2 x+1) u \pi}{2 N} \quad x=0,1, \cdots, N-1
其中C(u)=\left\{\begin{array}{lc}\frac{1}{\sqrt{2}} & u=0 \\1 & u=1,2, \ldots, N-1\end{array}\right.
B:实例
如下,有一长为4的数组序列,求其DFT
F(u)=C(u) \sqrt{\frac{2}{4}} \sum_{x=0}^{3} f(x) \cos \frac{(2 x+1) u \pi}{8} \quad u=0,1,2,3
如下
矩阵形式如下
(2)二维DCT
A:定义
二维DCT变换与逆变换定义:二维离散余弦变换(DCT)是一维DCT向二维的扩展。它用于将二维信号或图像转换为二维频域中的一组频率系数。总之,二维DCT是一种数学变换,它为给定的输入图像计算一组频率系数,使用具有不同水平和垂直频率的余弦函数的加权和。由此产生的频率系数可用于分析和压缩输入图像,以及其他应用
- f(x, y)代表输入图像,它由M行和N列的像素组成
- DCT用于将该输入图像转换为一组频率系数F(u, v),其中u和v分别为水平和垂直方向上的频率系数的指数
- 二维DCT的方程式与一维DCT的方程式相似,但在二维输入图像上有一个额外的求和。求和中的余弦函数由指数u、v、x和y设置参数,其参数分别由\frac{\pi(2x+1)u}{2M} 和 \frac{\pi(2y+1)v}{2N}给出。余弦函数被用来提取输入图像的水平和垂直频率分量,并通过求和来计算每个像素对每个频率系数的贡献
- 因子\frac{2}{\sqrt{MN}}、C(u)和C(v)是归一化常数,确保DCT是一种正交变换,输入图像的能量被保留下来。这些常数取决于指数u、v和正在使用的DCT的变体
其中
\begin{array}{c}x, u=0,1,2, \cdots, M-1 \\y, v=0,1,2, \cdots, N-1 \\C(u), C(v)=\left\{\begin{array}{ll}\frac{1}{\sqrt{2}} & u, v=0 \\1 & u, v=1,2, \ldots, N-1\end{array}\right.\end{array}
二维DCT变换的矩阵形式表示为
F=AfA^{T},f=A^{T}FA
B:实例
如下有一幅输入图像f(x,y),使用矩阵算法求其DCT
如下
C:程序
MATLAB实现:相关函数如下,具体解释可看MATLAB帮助手册
dct
:这个函数计算给定输入信号或序列的一维离散余弦变换(DCT)。DCT用于将输入信号转换为频域中的一组频率系数。DCT函数需要以下参数Src
:输入信号或序列dst
:输出频率系数flags
:一组控制DCT行为的标志nonzeroRows
:输入信号中非零行的数量(可选)
idct
:该函数计算一组给定频率系数的一维离散余弦逆变换(IDCT)。IDCT用于将频率系数转换回原始信号或序列。idct函数接收以下参数src
:输入频率系数dst
:输出信号或序列flags
:一组控制IDCT行为的标志nonzeroRows
:输入频率系数中非零行的数量(可选)
dct2
:该函数计算给定输入图像的二维离散余弦变换(DCT)。DCT用于将输入图像转换为二维频域中的一组频率系数。dct2函数接受以下参数src
:输入图像dst
:输出频率系数flags
:一组控制DCT行为的标志nonzeroRows
:输入图像中非零行的数量(可选)nonzeroCols
:输入图像中非零列的数量(可选)
idct2
:这个函数计算一组给定频率系数的二维离散余弦逆变换(IDCT)。IDCT用于将频率系数转换回原始图像。idct2函数接受以下参数src
:输入频率系数dst
:输出图像flags
:一组控制IDCT行为的标志nonzeroRows
:输入频率系数中非零行的数量(可选)nonzeroCols
:输入频率系数中非零列的数量(可选)
实现如下效果
Image=imread('cameraman.jpg');%读取图像
imshow(Image);%显示原图像
grayI=rgb2gray(Image);%将彩色图像灰度化
figure,imshow(grayI);
DCTI=dct2(grayI);%计算余弦变换并移位
ADCTI=abs(DCTI);
top=max(ADCTI(:));
bottom=min(ADCTI(:));
ADCTI=(ADCTI-bottom)/(top-bottom)*100;
figure,imshow(ADCTI);%显示余弦变换频谱图
imwrite(ADCTI,'cameramandct.jpg');
Python实现:使用Python实现上述同样的功能
cv2.dct
:DCTcv2.idct
:IDCT
import cv2
import numpy as np
from matplotlib import pyplot as plt
# 读取图像
Image = cv2.imread('cameraman.jpg')
# 显示原图像
cv2.imshow('Original Image', Image)
cv2.waitKey(0)
# 将彩色图像灰度化
grayI = cv2.cvtColor(Image, cv2.COLOR_BGR2GRAY)
# 显示灰度图像
cv2.imshow('Grayscale Image', grayI)
cv2.waitKey(0)
# 计算离散余弦变换
DCTI = cv2.dct(np.float32(grayI))
# 计算幅值并将其归一化到0-100之间
ADCTI = cv2.convertScaleAbs(DCTI)
ADCTI = cv2.normalize(ADCTI, None, 0, 100, cv2.NORM_MINMAX)
# 显示余弦变换频谱图
plt.imshow(ADCTI, cmap='gray')
plt.show()
# 保存离散余弦变换频谱图
cv2.imwrite('cameramandct.jpg', ADCTI)
(3)DCT在图像处理中的应用
DCT在图像处理中的应用:
- 图像压缩:DCT常用于图像压缩中,它基于图像的统计特征,将图像数据压缩到更少的存储空间中,而且在重建过程中,可以几乎无损地还原原始图像
- 图像水印:DCT可以用于图像水印的嵌入、提取和检测。通过将图像做DCT变换,然后将水印数据嵌入到DCT域的系数值中,以实现图像水印功能
- 图像特征提取:DCT可以用于图像的特征提取,在图像分类、图像识别、目标追踪等领域中有广泛的应用。在DCT域中,最大的系数值通常表示最明亮、最精细的细节,因此可以用于提取图像的特征
- 图像去噪:噪声常常会影响图像的质量和信息,DCT可以用于去除图像的高频噪声,以及平滑图像的细节信息,从而实现图像去噪的目的
二:K-L变换(Karhunen-Loeve Transform)
K-L变换(Karhunen-Loeve Transform):是建立在统计特性基础上的一种变换,又称为霍特林(Hotelling)变换或主成分分析(PCA)。K-L变换的突出优点是相关性好,是均方误差(MSE,Mean Square Error)意义下的最佳变换,它在数据压缩技术中占有重要地位
注意:K-L变换和主成分分析关系虽然很密切,但不能说是一回事
- K-L变换:是一种数学技术,它将一个给定的信号分解成一组正交的基础函数,称为特征函数。它是以数学家Richard Kullback和Solomon Linnik的名字命名的,他们在20世纪50年代首次描述了它。K-L变换被广泛用于信号处理、图像压缩和数据分析
- PCA:PCA是一种统计技术,用于通过寻找捕捉数据中最大变化量的最重要特征来降低数据集的维度。它通常被用于数据可视化、数据压缩和机器学习
PCA与K-L变换密切相关,因为这两种技术都涉及寻找协方差矩阵的特征向量和特征值。事实上,从PCA得到的主成分是协方差矩阵的特征向量,而特征值代表每个主成分所捕获的方差量。综上所述,虽然K-L变换和PCA有一些相似之处,但它们并不完全是一回事。K-L变换是一种用于信号处理的数学技术,而PCA是一种用于降维和特征提取的统计技术。
(1)K-L变换原理
A:K-L展开式
假设有一个二维随机向量 \mathbf{x} = [x_1, x_2],其均值为 \boldsymbol{\mu} = [\mu_1, \mu_2],协方差矩阵为 \mathbf{C}_{\mathbf{x}}。K-L 展开的目的是找到一组正交基函数 {\phi_i(\mathbf{x})},使得随机向量 \mathbf{x} 可以被表示为
\mathbf{x}=\boldsymbol{\mu}+\sum_{i=1}^{\infty} z_{i} \sqrt{\lambda_{i}} \boldsymbol{\phi}_{i}(\mathbf{x})
其中,{z_i} 是一组独立同分布的随机变量,{\boldsymbol{\phi}_i(\mathbf{x})} 是一组标准正交函数,\lambda_i 是 \mathbf{C}_{\mathbf{x}} 的第 i 个特征值,\phi_i(\mathbf{x}) 是 \mathbf{C}_{\mathbf{x}} 的第 i 个特征向量
由于特征向量 {\boldsymbol{\phi}_i(\mathbf{x})} 是标准正交函数,因此 K-L 展开保证了展开系数 z_i 是独立的。此外,K-L 展开中的基函数 {\boldsymbol{\phi}_i(\mathbf{x})} 是协方差矩阵 \mathbf{C}_{\mathbf{x}} 的特征向量,因此它们对应的是数据中的主成分,可以用于数据降维和特征提取等任务
K-L 展开的实现可以通过对协方差矩阵进行特征值分解得到。在实际应用中,由于数据维度往往很高,因此需要使用一些数值技巧来加速计算,例如矩阵的迹技巧和 Lanczos 迭代等
B:离散K-L变换
离散K-L变换(Discrete Karhunen-Loève Transform,DKLT):是 K-L 变换在离散信号处理中的一种形式。它将离散信号表示为一组正交基函数的线性组合,类似于离散余弦变换(DCT)和离散小波变换(DWT)
设有一个 N 维离散信号 \mathbf{x} = [x_1, x_2, \cdots, x_N],其均值为 \mu = \frac{1}{N}\sum_{i=1}^{N}x_i,协方差矩阵为 \mathbf{C}_\mathbf{x}。DKLT 的目的是找到一组正交基函数 {\boldsymbol{\phi}_i(\mathbf{x})},使得信号 \mathbf{x} 可以被表示为
\mathbf{x}=\boldsymbol{\mu}+\sum_{i=1}^{\infty} z_{i} \sqrt{\lambda_{i}} \boldsymbol{\phi}_{i}(\mathbf{x})
其中,{z_i} 是一组独立同分布的随机变量,\boldsymbol{\phi}_i(\mathbf{x}) 是信号 \mathbf{x} 的第 i 个正交基函数,\lambda_i 是 \mathbf{C}_{\mathbf{x}} 的第 i 个特征值
在实际应用中,由于离散信号的维度往往很高,因此需要使用数值方法来计算 DKLT。一种常用的方法是使用矩阵特征值分解。设 \mathbf{X} 是将信号 \mathbf{x} 按列排成的 N\times N 矩阵,\mathbf{\Lambda} 是协方差矩阵 \mathbf{C}_{\mathbf{x}} 的特征值对角矩阵,\mathbf{U} 是 \mathbf{C}_{\mathbf{x}} 的特征向量组成的矩阵,则 DKLT 的系数 {z_i} 可以通过以下公式计算
\mathbf{z}=\mathbf{U}^{T}(\mathbf{X}-\boldsymbol{\mu})
其中,\boldsymbol{\mu} 是信号 \mathbf{x} 的均值向量。然后,可以通过以下公式将信号 \mathbf{x} 进行还原
\mathbf{x}=\mathbf{\mu}+\mathbf{Uz}
与其他离散变换类似,DKLT 可以用于信号压缩、数据降维和特征提取等领域
C:程序
clc,clear;
X=[0 0 0;1 0 1;1 0 0;1 1 0;0 0 1;0 1 1;0 1 0;1 1 1]';
[n, N]=size(X);
V=X*X'/N;
[coeff, D]=eigs(V);
[D_sort,index] = sort(diag(D),'descend');
D=D(index,index);
coeff = coeff(:,index);
score=coeff'*X;
figure; plot(score(1,:),score(2,:),'ko'),title('K-L变换');
xlabel('第一主成分得分');ylabel('第二主成分得分');
(2)图像K-L变换
A:原理
图像K-L变换:是一种将图像转换到一个新的基下的线性变换,旨在提取图像的主要特征。其数学表达式与离散 K-L 变换类似,但是在图像处理中需要将信号扩展到两维
设有一幅 M \times N 的灰度图像 \mathbf{I},其均值为 \mu,协方差矩阵为 \mathbf{C_I}。图像 K-L 变换的目的是找到一组正交基函数 {\boldsymbol{\phi}_{i,j}(\mathbf{I})},使得图像 \mathbf{I} 可以被表示为
\mathbf{I}=\mu+\sum_{i=1}^{M} \sum_{j=1}^{N} z_{i, j} \sqrt{\lambda_{i, j}} \phi_{i, j}(\mathbf{I})
其中,{z_{i,j}} 是一组独立同分布的随机变量,\boldsymbol{\phi}_{i,j}(\mathbf{I}) 是图像 \mathbf{I} 的第 (i,j) 个正交基函数,\lambda_{i,j} 是 \mathbf{C_I} 的第 (i,j) 个特征值
在实际应用中,通常采用二维离散余弦变换(2D-DCT)作为正交基函数。具体来说,对于一幅 M \times N 的图像 \mathbf{I},可以将其分解为 M 个行向量和 N 个列向量,然后对每一行和每一列分别进行一维离散余弦变换。设变换后的结果为 \mathbf{F},则 \mathbf{F} 的第 (i,j) 个元素为
\begin{array}{l}F_{i, j}=\sqrt{\frac{2}{M N}} \cos \left[\frac{(2 i-1)(j-1) \pi}{2 M}\right] \cos \left[\frac{(2 j-1)(i-1) \pi}{2 N}\right] \sum_{m=1}^{M} \sum_{n=1}^{N}\left(I_{m, n}-\right. \mu) \cos \left[\frac{(2 m-1)(i-1) \pi}{2 M}\right] \cos \left[\frac{(2 n-1)(j-1) \pi}{2 N}\right]\end{array}
其中,I_{m,n} 是原始图像 \mathbf{I} 的第 (m,n) 个像素值。由于 DKLT 是一种正交变换,因此它可以保持图像的信息不变,但是将其表示为更加紧凑的形式。在实际应用中,图像 K-L 变换可以用于图像压缩、特征提取、图像分类等领域
B:程序
MATLAB实现:相关函数如下,具体解释可看MATLAB帮助手册
clear,clc,close all;
fmt={'*.jpg','JPEG image(*.jpg)';'*.*','All Files(*.*)'};
[FileName,FilePath]=uigetfile(fmt,'导入数据','face*.jpg','MultiSelect','on');
if ~isequal([FileName,FilePath],[0,0])
FileFullName=strcat(FilePath,FileName);
else
return;
end
N=length(FileFullName);
for k=1:N
Image=im2double(rgb2gray(imread(FileFullName{k})));
X(:,k) = Image(:); % 把图像放在矩阵x的第k列
end
[h,w,c]=size(Image);
% %----------- 计算每幅训练图像的与平均脸的差值 -------%
averagex = mean(X')'; %计算均值图像
X=X-averagex; % 求中心化图像向量
%-----奇异值分解方法计算协方差矩阵的特征值和特征向量----%
R = X'*X; %协方差矩阵为x*x’,这里用奇异值分解
[Q,D] = eig(R); %V为以特征向量为列的矩阵,D为特征值组成的对角阵
[D_sort,index] = sort(diag(D),'descend');
D=D(index,index);
Q = Q(:,index);
P = X*Q*(abs(D))^-0.5;
total = 0.0;
count = sum(D_sort);
for r =1:N
total = total + D_sort(r);
if total/count > 0.95 %当差异信息比例达到85%时退出循环
break;
end
end
%-------------测试样本在新空间上投影后的坐标-----------%
KLCoefR = P'*X;
figure; plot(KLCoefR(1,:),KLCoefR(2,:),'ko'),title('K-L变换行压缩');
xlabel('第一主成分得分');ylabel('第二主成分得分');
Y= P(:,1:2)*KLCoefR(1:2,:)+averagex; %重建
for j=1:N
outImage=reshape(Y(:,j),h,w);
% top=max(outImage(:));
% bottom=min(outImage(:));
% outImage=(outImage-bottom)/(top-bottom);
% str=strcat('feaface12_',num2str(j),'.jpg');
% imwrite(outImage,str);
figure,imshow(outImage,[]);
end
Z= P(:,1:r)*KLCoefR(1:r,:)+averagex; %重建
for j=1:N
outImage=reshape(Z(:,j),h,w);
% top=max(outImage(:));
% bottom=min(outImage(:));
% outImage=(outImage-bottom)/(top-bottom);
% str=strcat('feaface1r_',num2str(j),'.jpg');
% imwrite(outImage,str);
figure,imshow(outImage,[]);
end
KLCoefC = X*Q;
for j =1:N
outImage=reshape(KLCoefC(:,j),h,w);
% top=max(outImage(:));
% bottom=min(outImage(:));
% outImage=(outImage-bottom)/(top-bottom);
% str=strcat('feaface',num2str(j),'.jpg');
% imwrite(outImage,str);
figure,imshow(outImage,[]);
end
%
%
Python实现:使用Python实现上述同样的功能
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 导入数据
fmt = [("*.jpg", "JPEG image(*.jpg)"), ("*.*", "All Files(*.*)")]
FileName, FilePath = tkinter.filedialog.askopenfilename(filetypes=fmt, title="导入数据", initialdir=".", multiple=True)
if FileName:
N = len(FileName)
X = np.zeros((h * w, N))
for k in range(N):
Image = cv2.imread(FileName[k])
Image = cv2.cvtColor(Image, cv2.COLOR_BGR2GRAY).astype(np.float64)
X[:, k] = np.reshape(Image, -1) # 把图像放在矩阵x的第k列
[h, w] = Image.shape
# 计算每幅训练图像的与平均脸的差值
averagex = np.mean(X, axis=1)
X = X - np.tile(averagex[:, np.newaxis], (1, N))
# 奇异值分解方法计算协方差矩阵的特征值和特征向量
R = np.dot(X.T, X)
[D, Q] = np.linalg.eigh(R) # Q为以特征向量为列的矩阵,D为特征值组成的对角阵
idx = D.argsort()[::-1]
D = D[idx]
Q = Q[:, idx]
P = np.dot(X, Q)
P = np.dot(P, np.diag(1 / np.sqrt(abs(D) + np.finfo(np.float32).eps))) # 使P正交
total = 0.0
count = np.sum(D)
for r in range(N):
total += D[r]
if total / count > 0.95:
break
# 测试样本在新空间上投影后的坐标
KLCoefR = np.dot(P.T, X)
plt.plot(KLCoefR[0, :], KLCoefR[1, :], "ko")
plt.title("K-L变换行压缩")
plt.xlabel("第一主成分得分")
plt.ylabel("第二主成分得分")
plt.show()
Y = np.dot(P[:, :2], KLCoefR[:2, :]) + np.tile(averagex[:, np.newaxis], (1, N)) # 重建
for j in range(N):
outImage = np.reshape(Y[:, j], (h, w))
plt.imshow(outImage, cmap="gray")
plt.show()
Z = np.dot(P[:, :r], KLCoefR[:r, :]) + np.tile(averagex[:, np.newaxis], (1, N)) # 重建
for j in range(N):
outImage = np.reshape(Z[:, j], (h, w))
plt.imshow(outImage, cmap="gray")
plt.show()
KLCoefC = np.dot(X, Q)
for j in range(N):
outImage = np.reshape(KLCoefC[:, j], (h, w))
plt.imshow(outImage, cmap="gray")
plt.show()
评论区