什么是DCT?
一维DCT变换
一维DCT变换时二维DCT变换的基础,所以我们先来讨论下一维DCT变换。一维DCT变换共有8种形式,其中最常用的是第二种形式,由于其运算简单、适用范围广。我们在这里只讨论这种形式,其表达式如下:
其中,f(i)为原始的信号,F(u)是DCT变换后的系数,N为原始信号的点数,c(u)可以认为是一个补偿系数,可以使DCT变换矩阵为正交矩阵。
其中,f(i)为原始的信号,F(u)是DCT变换后的系数,N为原始信号的点数,c(u)可以认为是一个补偿系数,可以使DCT变换矩阵为正交矩阵。
二维DCT变换
二维DCT变换其实是在一维DCT变换的基础上在做了一次DCT变换,其公式如下:
由公式我们可以看出,上面只讨论了二维图像数据为方阵的情况,在实际应用中,如果不是方阵的数据一般都是补齐之后再做变换的,重构之后可以去掉补齐的部分,得到原始的图像信息,这个尝试一下,应该比较容易理解。
另外,由于DCT变换高度的对称性,在使用Matlab进行相关的运算时,我们可以使用更简单的矩阵处理方式:
二维DCT逆变换
在图像的接收端,根据DCT变化的可逆性,我们可以通过DCT反变换恢复出原始的图像信息,其公式如下:
同样的道理,我们利用之前的矩阵运算公司可以推导出DCT反变换相应的矩阵形式
对二维图像进行离散余弦变换
由以上对二维离散余弦变换的定义及公式(7)可知,求二维图像的离散余弦变换要进行以下步骤:
- 1.获得图像的二维数据矩阵f(x,y);
- 2.求离散余弦变换的系数矩阵[A];
- 3.求系数矩阵对应的转置矩阵[A]T;
- 4.根据公式(7)[F(u,v)]=[A][f(x,y)][A]T 计算离散余弦变换;
优点
1、DCT变换较DFT变换具有更好的频域能量聚集度(说人话就是能够把图像更重要的信息聚集在一块),那么对于那些不重要的频域区域和系数就能够直接裁剪掉(有点像淘金,你把石头里重要的金子都弄到一块,剩下没啥用的石子不就可以扔了么),因此,DCT变换非常适合于图像压缩算法的处理,例如现在大名鼎鼎的jpeg就是使用了DCT作为图像压缩算法
2、DCT变换是可分离的变换,其变换核为余弦函数。DCT除了具有一般的正交变换性质外, 它的变换阵的基向量能很好地描述人类语音信号和图像信号的相关特征。因此,在对语音信号、图像信号的变换中,DCT变换被认为是一种准最佳变换。
二维DFT与二维DCT的频谱特征分析
1、细节(高频分量)较少的图像实验:
Conclusion:
对于比较平滑的图像/数据,DFT变换数据集中在中间(低频信号区),DCT变换数据集中在左上角,几乎无法看出DCT的优势在哪里。
2、细节丰富的图像实验
Conclusion:
DCT变化后的数据很发散,DCT变化后的数据仍然比较集中。如果同样从频率谱恢复原始图像,那么选用DCT更合理,因为DCT只需要存储更少的数据点。正是这个原因,是的DCT广泛地应用于图像压缩。
应用
DCT应用于图像压缩
16*16 进行分区做DCT变换,然后按照不同的模板进行数据存留与重建。我们会发现,如果保存的数据过少,会有块效应现象发生。
64*64的分区设置,块效应更明显。此时就要在每个分区内多采集点数据。
DCT在JPEG压缩编码中的应用
DCT又称离散余弦变换,是一种块变换方式,只使用余弦函数来表达信号,与傅里叶变换紧密相关。常用于图像数据的压缩,通过将图像分成大小相等(一般为8*8)的块,利用DCT对其进行变换,得到更加简洁的数据。因为图像像素间存在较大的空间相关性,DCT可以大大减小这些相关性,使图像能量集中在左上角区域,从而利于数据压缩。变换后得到的数据称为DCT系数。这一过程是无损的。
根据人类视觉系统理论,人眼对图像平滑区域的变换比较敏感,而对纹理区域的变换不太敏感,经过离散余弦变换之后,图像信息集中在少数低频系数上,而纹理和边缘信息则在中低频系数中,所以低频系数的改变对图像视觉 上的影响远大于高频系数。
DCT变换将图像信号从空间域变换到频域,是JPEG(有损图像数字压缩技术)的核心步骤。
在 JPEG压缩中,为了在图像画面降质不明显的前提下获得较高的压缩比,保留的恰是对人眼视觉重要的低频系数,而将大部分高频系数变成了零, 因此 JPEG压缩对低频系数不敏感,而对高频系数敏感, 将信息数据嵌入在高频部分可能在有损压缩中丢 失, 作为一种权衡,可以将信息嵌入在图像的中频系数之间
图像经过DCT变换后,空域中的总能量在变换域中得到保持,但像素之 间的相关性下降,能量将会重新分布,由空域中所表现出的能量发散形式变换为频域能量相对集中的形式,并集中在变换域的低频系数上。
JPEG算法的主要计算步骤:
- 正向离散余弦变换(FDCT)
- 量化(quantization)
- Z字形编码(zigzag scan)
- 使用差分脉冲编码调制(differential pulse code modulation,DPCM)对直流系数(DC)进行编码
- 使用行程长度编码(run-length encoding,RLE)对交流系数(AC)进行编码
- 熵编码(entropy coding)
DCT在数字水印中的应用
水印检测框图:
实验
matlab基础
DCT变换1
%读入测试图像 mypicture=imread('input.jpg');%显示读入的图像 %为了防止后一个显示的图像覆盖前一个显示结果,每次显示时调用figure生成一个新窗口 figure(),imshow(mypicture),title('原输入图像');
图一
转为灰度图:
grayImage=rgb2gray(mypicture);%如果读入的是彩色图像则转化为灰度图像(灰度图像省略这一步) figure(),imshow(grayImage),title('原输入彩色图像转化为灰度图像');
图二
对图像DCT转换:
%对图像DCT变换 dctgrayImage=dct2(grayImage); figure(), imshow(log(abs(dctgrayImage)),[]),title('DCT变换灰度图像'), colormap(gray(4)), colorbar;
图三
对灰度矩阵进行量化:
%对灰度矩阵进行量化 dctgrayImage(abs(dctgrayImage)<0.1)=0;
DCT逆变换:
%DCT逆变换 I=idct2(dctgrayImage)/255; figure(), imshow(I), title('经过DCT变换,然后逆变换的灰度图像');
图四
对比变换傅里叶变换前后的图像 :
%对比变换傅里叶变换前后的图像 figure(), subplot(121), imshow(grayImage), title('原灰度图像'), subplot(122), imshow(I), title('DCT逆变换图像');
图五
结果分析:对原始图像进行离散余弦变换,如图3所示,由结果可知,变换后DCT系数能量主要集中在左上角,其余大部分系数接近于零,这说明DCT具有适用于图像压缩的特性。将变换后的DCT系数进行门限操作,将小于一定值得系数归零,这就是图像压缩中的量化过程,然后进行逆DCT运算,得到压缩后的图像,如图4。由图5比较变换前后的图像,肉眼很难分辨出有什么区别,可见压缩的效果比较理想
DCT变换2
image=imread('input.jpg'); figure; subplot(2,4,1),imshow(image),title("原图"); grayI=rgb2gray(image); subplot(2,4,2),imshow(grayI),title("灰度图"); DCTI=dct2(grayI); subplot(2,4,3),imshow(DCTI),title("DCT变换"); ADCTI=abs(DCT1); subplot(2,4,4),imshow(ADCTI),title("取绝对值"); top=max(ADCTI(:)); subplot(2,4,5),imshow(top),title("取最大值"); bottom=min(ADCTI(:)); subplot(2,4,6),imshow(bottom),title("取最小值"); ADCTI=(ADCTI-bottom)/(top-bottom)*100; subplot(2,4,7),imshow(ADCTI),title("量化后"); IDCTI=idct2(DCTI)/255; subplot(2,4,8),imshow(IDCTI),title("DCT逆变换");
所以,能量主要分布在左上角低频分量处
DCT图像压缩
打开一幅图像,对其进行DCT变换,将高频置零并进行反变换
image=imread('input.jpg'); figure; subplot(2,2,1),imshow(image),title("原图"); grayI=rgb2gray(image); subplot(2,2,2),imshow(grayI),title("灰度图"); DCTI=dct2(grayI); subplot(2,2,3),imshow(DCTI),title("DCT变换"); [h,w]=size(DCTI); cf=60; FDCTI=zeros(h,w); FDCTI(1:cf,1:cf)=DCTI(1:cf,1:cf); gratOut=uint8(abs(idct2(FDCTI))); subplot(2,2,4),imshow(gratOut),title("压缩重建后");
彩色图像转灰度图
彩图转灰度图有两种方法:
1、使用rgb2gray()
将RGB三个分量的数值相等,输出后就是灰度图
2、使用ycbcr()
将Y分量提取出,YCBCR格式中的Y分量表示是图像中的亮度和浓度,所以只需输出Y分量,得到的就是图像的灰度图
具体来讲:
YCbCr是通过有序的三元组来表示的,三元由Y(Luminance)、Cb(Chrominance-Blue)和Cr(Chrominance-Red)组成,其中Y表示颜色的明亮度和浓度,而Cb和Cr则分别表示颜色的蓝色浓度偏移量和红色浓度偏移量。人的肉眼对由YCbCr色彩空间编码的视频中的Y分量更敏感,而Cb和Cr的微小变化不会引起视觉上的不同,根据该原理,通过对Cb和Cr进行子采样来减小图像的数据量,使得图像对存储需求和传输带宽的要求大大降低,从而达到在完成图像压缩的同时也保证了视觉上几乎没有损失的效果,进而使得图像的传输速度更快,存储更加方便。我们要的到灰度图像,首先要将采集到的彩色图像转化为YCbCr。
这是OV7725的手册中给出的RGB888 to YCbCr的算法公式。简单明了,将一副图片的RGB分量提取出来,然后用上面的公式进行运算,得到YcbCr分量,然后在合成显示即可。这样显示出来的是YcbCr色彩空间的图片,我们只取Y分量作为新的图片的三个分量合成,得到的即是这幅彩色图片的灰度图。
%将一幅640*480的彩色图片转换成显示成灰度显示? clc; clear all; close all; RGB_data = imread('input.jpg');%图像读入 R_data = RGB_data(:,:,1); G_data = RGB_data(:,:,2); B_data = RGB_data(:,:,3); figure; subplot(1,2,1),imshow(RGB_data),title("原图"); [ROW,COL, DIM] = size(RGB_data); %提取图片的行列数 Y_data = zeros(ROW,COL); Cb_data = zeros(ROW,COL); Cr_data = zeros(ROW,COL); Gray_data = RGB_data; %YCbCr_data = RGB_data; for r = 1:ROW for c = 1:COL Y_data(r, c) = 0.299*R_data(r, c) + 0.587*G_data(r, c) + 0.114*B_data(r, c); Cb_data(r, c) = -0.172*R_data(r, c) - 0.339*G_data(r, c) + 0.511*B_data(r, c) + 128; Cr_data(r, c) = 0.511*R_data(r, c) - 0.428*G_data(r, c) - 0.083*B_data(r, c) + 128; end end Gray_data(:,:,1)=Y_data; Gray_data(:,:,2)=Y_data; Gray_data(:,:,3)=Y_data; subplot(1,2,2),imshow(Gray_data),title("YCBCR转灰度图");
DCT分块变换
1、使用dct2()
% 读取灰度图像 img = imread('huidu.jpg'); % dct2 是2维dct变换函数,得到一个与图像大小相同的二维矩阵 dct_mtx = dct2(img); % idct2 是逆2维dct变换函数,得到原图像矩阵 img_idct = idct2(dct_mtx)/255; figure; subplot(1,3,1),imshow(img),title("原图"); subplot(1,3,2),imshow(dct_mtx),title("DCT变换"); subplot(1,3,3),imshow(img_idct),title("DCT还原");
2、使用dctmtx()
io = double(imread("huidu.jpg")); T = dctmtx(8); % 对载体图像进行DCT变换 DCT_org = blkproc(io,[8 8], 'P1*x*P2',T, T'); % 对DCT 矩阵进行逆变换 DCT_reverse = blkproc(DCT_org,[8 8], 'P1*x*P2',T', T); figure; subplot(1,3,1),imshow(io),title("原图"); subplot(1,3,2),imshow(DCT_org),title("DCT分块变换"); subplot(1,3,3),imshow(DCT_reverse),title("DCT分块还原");
DCT可逆信息隐藏
原理:利用DCT变换的矩阵进行操作,有很多种方法,这里举出其中一种方法【原始图像有损,提取信息无损】
隐藏方法:主要是利用载体中两个特定数的相对大小来表示隐藏信息。发送方和接收方事先约定好嵌入过程中所使用的两个DCT系数的位置(为了隐藏的健壮性和不可觉察性,这两个 DCT 系数应该在 DCT 的中频系数中选择)。例如,设定(u,v) 和 (m,n) 为所选定的两个系数的坐标。嵌入过程为:如果Bi(u,v)> Bi(m,n) ,就代表隐藏信息“1”,如果 Bi(u,v)< Bi(m,n) 就代表 隐 藏 信 息“0”。
如 果 需 要 隐 藏 的 信 息 位 为 1,但 是Bi(u,v)<Bi(m,n) 那么就把这两个系数交换,最后发送方通过二维逆DCT变换将图像转化为空间域进行传输。
提取方法:接收方接收到图像后,对图像进行二维DCT变换,通过比较每一块中约定位置的DCT系数的相对大小,得到隐藏信息的比特串,从而提取出秘密信息。
% DCT 变换信息隐藏 io = imread("huidu.jpg"); figure; subplot(1,3,1),imshow(io),title("原图"); io = double(io); % 待嵌入的秘密信息msg msg = [1,0,1,1]; % 用于计数,嵌入完成后停止操作。 count = length(msg); org_msg = [1,0,1,1]; T = dctmtx(8); %图像分块8*8 DCTrgb = blkproc(io,[8 8], 'P1*x*P2',T, T'); % 对载体图像进行DCT变换 subplot(1,3,2),imshow(DCTrgb),title("DCT分块变换"); [row,col]=size(DCTrgb); row=floor(row/8); col=floor(col/8); alpha=0.02; k = 1; temp=0; for i=0:(row - 1) for j=0: (col -1) irow = i * 8; jcol = j * 8; if k <= count if msg(k) == 0 %选择(5,2),(4,3)这两对系数, % 策略是(5,2)的DCT系数 < (4,3)时,表示嵌入了0 % 如果(5,2) > (4,3) 那我们把两个系数交换,还表示嵌入了0 if DCTrgb(irow + 5, jcol + 2) < DCTrgb(irow + 4,jcol + 3) temp = DCTrgb(irow + 5, jcol + 2); DCTrgb(irow + 5, jcol + 2) = DCTrgb(irow + 4,jcol + 3); DCTrgb(irow + 4, jcol + 3) = temp; end else if DCTrgb(irow + 5, jcol + 2) > DCTrgb(irow + 4,jcol + 3) temp = DCTrgb(irow + 5, jcol + 2); DCTrgb(irow + 5, jcol + 2) = DCTrgb(irow + 4,jcol + 3); DCTrgb(irow + 4, jcol + 3) = temp; end end %将原本小的系数变的更小,使系数差变大 if DCTrgb(irow + 5, jcol + 2) < DCTrgb(irow + 4,jcol +3) DCTrgb(irow + 5, jcol + 2) = DCTrgb(irow +5, jcol +2) - alpha; else DCTrgb(irow + 4, jcol + 3) = DCTrgb(irow + 4, jcol +3) - alpha; end k = k + 1; end end end wi=blkproc(DCTrgb,[8 8],'P1*x*P2',T',T); %嵌入信息的载体DCT变换,恢复图像 orgin_wi=wi/255; subplot(1,3,3),imshow(orgin_wi),title("嵌入信息后的"); % 提取消息 % ext_msg是提取出的秘密信息 ext_msg = []; T=dctmtx(8); DCTcheck=blkproc(wi,[8 8],'P1*x*P2',T,T'); %对隐秘图像进行DCT变换 [row,col]=size(DCTcheck); row=floor(row/8); col=floor(col/8); k = 1; for i=0:(row - 1) for j=0: (col -1) irow = i * 8; jcol = j * 8; %通过比较(5,2),(4,3)这两对系数,判断隐藏的信息是1还是0 if k <= count if DCTcheck(irow + 5, jcol + 2) < DCTcheck(irow + 4,jcol + 3) ext_msg(k,1)=1; end if DCTcheck(irow + 5, jcol + 2) > DCTcheck(irow + 4,jcol + 3) ext_msg(k,1)=0; end k = k + 1; end end end fprintf("嵌入的信息:"); disp(msg); fprintf("提取的信息:"); disp(ext_msg);
参考
1、百度百科
2、知乎
5、Matlab实现