dct图像压缩c语言实现,DCT变换在图像压缩中的实现

小白拙见,希望理解不对的地方大家多多指教!

对于各种信号,都可以说它是由多个振幅与频率不同的正弦或者余弦函数组成的。并且一个信号通常由一个直流信号DC(幅值保持不变的信号)和多个交流信号AC(幅值以某种频率周期性变化的信号)组成。而通过离散余弦变换(DCT),就可以将一个源信号分解为DC分量和AC分量,求出它各个分量的系数。

对于DCT来说,其定义为:

一维变换:

0818b9ca8b590ca3270a3433284dd417.png

二维变换:

0818b9ca8b590ca3270a3433284dd417.png

0818b9ca8b590ca3270a3433284dd417.png

首先对于DCT公式里,它有一组基函数,并且这组基函数是正交的,也就是两两互相垂直,就像是三维空间中的x,y,z.比如一维里的cos(2i+1)uπ/16,这就是基函数,并且,随着u取不同的值,我们会得到不同的基函数,例如当u=0时,基函数是cos0=1,这也就说明,这个基函数没有波形变化,他对应的值都是1.但是当我们对u取1时,基函数就是cos(2i+1)π/16,此时,基函数的周期T=2π/(2π/16),周期为16,频率f=1/16.相同的,当u=2,3,4,5,6,7时,频率分别为2/16,3/16,4/16,5/16,6/16,7/16.这说明,这些基函数对应不同的频域,并且从u=0,到u=7,频率是在变大的。而一个源信号f(i),经过DCT变换,就是将这个源信号包含的这些不同频域的分量给求出来。并且前面说到,一个信号通常由一个DC和多个AC组成,到这里,我们可以看出,在u=0时,求出来的F(0)就是DC分量,其余的u=1,2,3,4,5,6,7时,求出的F(u)是AC分量。

而为什么DCT能把一个信号分解出来不同频域的分量值呢?这就相当于在三维向量中,基向量x(1,0,0); y(0,1,0) ; z(0,0,1)一样,在三维空间中,任意一个向量A都可以分解为A=ax+by+cz.这里面的x,y,z就是上面的基向量。而我们的DCT中的基向量组跟x,y,z一样,也是正交的,并且可以看出,由于每个基函数的频率不同,所以他们代表着的是不同的频域。通过变换,它也同样可以求出任意一个信号在各个频域上(类似三维空间,也可以说各个基向量方向上)对应的a,b,c......的值,而这些值,就是我们得到的DCT系数了,其中包括一个DC分量和多个AC分量,并且DC分量是代表频率最小的信号,AC1,AC2....AC7对应的是不断增大的频域上的信号。

而如果我们有个图像,我们知道,对于图像来说,其中的边缘,细节上的信号往往是变化比较快,比较剧烈的,所以,图像中的高频信号代表的是图像中的细节和边缘信息。而图像中的大部分内容信息,往往是变换缓慢,频率低的信号,所以,信号中的低频信号代表更多的图像信息。这样,我们就可以通过DCT,求出对应的不同频域分量,最后只保留低频低频,去掉高频数据对应的细节信息,就可以达到压缩的目的了。

例如一个8*8的图像块,其DCT变换后的数据,左上角为低频数据,右下角为高频数据,并且数据能量主要集中在低频区域,即低频区域的值比较大,高频区域的值较小。也就是因为高频区域值小,能量低,所以我们可以在接下来的压缩中,将他们置0,在图片质量看起来影响不大的情况下完成压缩。在这里,我们需要理解一下,为什么低频数据的值就比较大,而高频数据的值比较小呢?首先,对于获得的基函数,低频数值高于高频数值。在设定u=0时,其此时的基函数的取值都等于1,都为正数,如果源信号与此基函数频率相同或相近,那么他们相乘得到的系数将都是相对较大的值,在设定u=1时,其此时的基函数的取值大概为09,0.8,0.5,0.2,-0.2,-0.5,-0.8,-0.9有正数有负数,且绝对值都小于1,那么,对于一个与此信号频率相同的源信号,相乘后的结果较u=0时要小。所以在低频域内得到较大的数值。并且对于一个8*8的图像块非负数据,其最左上角的那个DC值,等于8乘上源信号的平均值;再者,在一般的图像中,低频数据量高于高频数据量,一幅图片中大多数数据,不论是亮度或者是色度,变化都不会很剧烈,所以,低频区域值较大,所占能量更高。

以下是MatlabDCT变换实现:

1、将整个图像整体进行DCT变换:

function [y] = Dct(x)

%图像的DCT变换效果对比

%对整个图片进行DCT变换,观察DCT系数能量分布情况

x=imread(‘Image1.bmp’);

x=rgb2gray(x);%转换成灰度图像

figure(1);imshow(x);title(‘原图’);

y=dct2(x); %计算DCT

figure(2);imshow(log(abs(y)),[]);title(‘DCT系数’);

colormap(gray(4));colorbar;

y(abs(y)<4)=0; %小于4的数值变为0

RD=idct2(y)/255; %反DCT

figure(3);imshow(RD);title(‘恢复图像’);

end

0818b9ca8b590ca3270a3433284dd417.png

0818b9ca8b590ca3270a3433284dd417.png

0818b9ca8b590ca3270a3433284dd417.png

由图可看,DCT系数能量集中在左上方的低频区域。并且对于一些高频数据,我们设置其为0后,图片的还原效果并未受到大的影响。

1、将图像整分成8*8的块进行DCT变换:

function [ y] = DCT_1( x )

%对图像进行分块的DCT变换

% 先将图片进行8*8分块,对每一块进行DCT变换。保留不同数量和部位的DCT系数,对比高频,低频系数对图像质量的影响;

% 将多个块分别反DCT,恢复原图,进行对比

x=imread(‘Image1.bmp’);

x=rgb2gray(x);

x=im2double(x);

t=dctmtx(8);

y = blkproc(x, [8 8], ‘P1 * x * P2’, t, t’);

figure(1);imshow(log(abs(y)),[]);title(‘DCT系数’);

mask1=[1 1 0 0 0 0 0 0

1 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0];%保留了3个

mask2=[1 1 1 1 0 0 0 0

1 1 1 0 0 0 0 0

1 1 0 0 0 0 0 0

1 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0];%保留了10

mask3=[1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 0

1 1 1 1 1 1 0 0

1 1 1 1 1 0 0 0

1 1 1 1 0 0 0 0

1 1 1 0 0 0 0 0

1 1 0 0 0 0 0 0

1 0 0 0 0 0 0 0];%保留了36

mask4=[ 1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1];%保留了全部

mask5=[ 0 0 1 1 1 1 1 1

0 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1];%保留了右下64-3

mask6=[ 0 0 0 0 1 1 1 1

0 0 0 1 1 1 1 1

0 0 1 1 1 1 1 1

0 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1

1 1 1 1 1 1 1 1];%保留了右下64-10

mask7=[ 0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 1

0 0 0 0 0 0 1 1

0 0 0 0 0 1 1 1

0 0 0 0 1 1 1 1

0 0 0 1 1 1 1 1

0 0 1 1 1 1 1 1

0 1 1 1 1 1 1 1];%保留了右下64-36

y1=blkproc(y,[8 8],’P1.*x’,mask1);

y2=blkproc(y,[8 8],’P1.*x’,mask2);

y3=blkproc(y,[8 8],’P1.*x’,mask3);

y4=blkproc(y,[8 8],’P1.*x’,mask4);

y5=blkproc(y,[8 8],’P1.*x’,mask5);

y6=blkproc(y,[8 8],’P1.*x’,mask6);

y7=blkproc(y,[8 8],’P1.*x’,mask7);

y11=blkproc(y1,[8 8],’P1*x*P2’,t’,t);

y22=blkproc(y2,[8 8],’P1*x*P2’,t’,t);

y33=blkproc(y3,[8 8],’P1*x*P2’,t’,t);

y44=blkproc(y4,[8 8],’P1*x*P2’,t’,t);

y55=blkproc(y5,[8 8],’P1*x*P2’,t’,t);

y66=blkproc(y6,[8 8],’P1*x*P2’,t’,t);

y77=blkproc(y7,[8 8],’P1*x*P2’,t’,t);

figure(2);subplot(2,4,1),imshow(x),title(‘原图’);

figure(2);subplot(2,4,2),imshow(y11),title(‘还原保留左上3’);

figure(2);subplot(2,4,3),imshow(y22),title(‘还原保留左上10’);

figure(2);subplot(2,4,4),imshow(y33),title(‘还原保留左上36’);

figure(2);subplot(2,4,5),imshow(y44),title(‘还原全部’);

figure(2);subplot(2,4,6),imshow(y55),title(‘还原保留右下63-3’);

figure(2);subplot(2,4,7),imshow(y66),title(‘还原保留右下63-10’);

figure(2);subplot(2,4,8),imshow(y77),title(‘还原保留右下63-36’);

end

0818b9ca8b590ca3270a3433284dd417.png

由DCT系数可以看出,每个数据块的能量集中在左上角处

对比:

0818b9ca8b590ca3270a3433284dd417.png

0818b9ca8b590ca3270a3433284dd417.png

0818b9ca8b590ca3270a3433284dd417.png

0818b9ca8b590ca3270a3433284dd417.png

通过上面的图片可知,只保留左上角三个数据,就可以得到一个相对完整的图片,而如果保留除左上角三个数据外的其他所有数据,也只得到了一些图像的边缘细节信息。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个基于离散余弦变换图像压缩C语言实现示例: ```c #include <stdio.h> #include <stdlib.h> #include <math.h> #define BLOCK_SIZE 8 #define IMAGE_SIZE 256 double C[BLOCK_SIZE][BLOCK_SIZE]; double C_t[BLOCK_SIZE][BLOCK_SIZE]; /* 初始化DCT系数矩阵 */ void init_DCT_matrix() { for(int i=0; i<BLOCK_SIZE; i++) { for(int j=0; j<BLOCK_SIZE; j++) { if(i == 0) { C[i][j] = sqrt(1.0/BLOCK_SIZE); } else { C[i][j] = sqrt(2.0/BLOCK_SIZE) * cos((2*j+1)*i*M_PI/(2.0*BLOCK_SIZE)); } C_t[j][i] = C[i][j]; } } } /* 对一个8x8的图像块进行DCT变换 */ void DCT(double img[BLOCK_SIZE][BLOCK_SIZE], double dct[BLOCK_SIZE][BLOCK_SIZE]) { double temp[BLOCK_SIZE][BLOCK_SIZE] = {0}; double temp2[BLOCK_SIZE][BLOCK_SIZE] = {0}; /* 对行进行DCT变换 */ for(int i=0; i<BLOCK_SIZE; i++) { for(int j=0; j<BLOCK_SIZE; j++) { double sum = 0; for(int k=0; k<BLOCK_SIZE; k++) { sum += img[i][k] * C[j][k]; } temp[i][j] = sum; } } /* 对列进行DCT变换 */ for(int i=0; i<BLOCK_SIZE; i++) { for(int j=0; j<BLOCK_SIZE; j++) { double sum = 0; for(int k=0; k<BLOCK_SIZE; k++) { sum += temp[k][i] * C_t[j][k]; } temp2[i][j] = sum; } } /* 将DCT系数矩阵赋值给输出矩阵 */ for(int i=0; i<BLOCK_SIZE; i++) { for(int j=0; j<BLOCK_SIZE; j++) { dct[i][j] = temp2[i][j]; } } } /* 对一个8x8的DCT系数矩阵进行逆DCT变换 */ void IDCT(double dct[BLOCK_SIZE][BLOCK_SIZE], double img[BLOCK_SIZE][BLOCK_SIZE]) { double temp[BLOCK_SIZE][BLOCK_SIZE] = {0}; double temp2[BLOCK_SIZE][BLOCK_SIZE] = {0}; /* 对行进行逆DCT变换 */ for(int i=0; i<BLOCK_SIZE; i++) { for(int j=0; j<BLOCK_SIZE; j++) { double sum = 0; for(int k=0; k<BLOCK_SIZE; k++) { sum += dct[i][k] * C_t[k][j]; } temp[i][j] = sum; } } /* 对列进行逆DCT变换 */ for(int i=0; i<BLOCK_SIZE; i++) { for(int j=0; j<BLOCK_SIZE; j++) { double sum = 0; for(int k=0; k<BLOCK_SIZE; k++) { sum += C[k][i] * temp[k][j]; } temp2[i][j] = sum; } } /* 将逆DCT变换后的像素矩阵赋值给输出矩阵 */ for(int i=0; i<BLOCK_SIZE; i++) { for(int j=0; j<BLOCK_SIZE; j++) { img[i][j] = temp2[i][j]; } } } /* 对整幅图像进行DCT变换 */ void compress_image(double img[IMAGE_SIZE][IMAGE_SIZE], double dct[IMAGE_SIZE][IMAGE_SIZE]) { init_DCT_matrix(); /* 对每个8x8的图像块进行DCT变换 */ for(int i=0; i<IMAGE_SIZE; i+=BLOCK_SIZE) { for(int j=0; j<IMAGE_SIZE; j+=BLOCK_SIZE) { double block[BLOCK_SIZE][BLOCK_SIZE] = {0}; double dct_block[BLOCK_SIZE][BLOCK_SIZE] = {0}; /* 将图像块赋值给一个8x8的矩阵 */ for(int x=0; x<BLOCK_SIZE; x++) { for(int y=0; y<BLOCK_SIZE; y++) { block[x][y] = img[i+x][j+y]; } } /* 对图像块进行DCT变换 */ DCT(block, dct_block); /* 将DCT系数矩阵赋值给输出矩阵 */ for(int x=0; x<BLOCK_SIZE; x++) { for(int y=0; y<BLOCK_SIZE; y++) { dct[i+x][j+y] = dct_block[x][y]; } } } } } /* 对整幅图像进行逆DCT变换 */ void decompress_image(double dct[IMAGE_SIZE][IMAGE_SIZE], double img[IMAGE_SIZE][IMAGE_SIZE]) { init_DCT_matrix(); /* 对每个8x8的DCT系数矩阵进行逆DCT变换 */ for(int i=0; i<IMAGE_SIZE; i+=BLOCK_SIZE) { for(int j=0; j<IMAGE_SIZE; j+=BLOCK_SIZE) { double block[BLOCK_SIZE][BLOCK_SIZE] = {0}; double img_block[BLOCK_SIZE][BLOCK_SIZE] = {0}; /* 将DCT系数矩阵赋值给一个8x8的矩阵 */ for(int x=0; x<BLOCK_SIZE; x++) { for(int y=0; y<BLOCK_SIZE; y++) { block[x][y] = dct[i+x][j+y]; } } /* 对DCT系数矩阵进行逆DCT变换 */ IDCT(block, img_block); /* 将逆DCT变换后的像素矩阵赋值给输出矩阵 */ for(int x=0; x<BLOCK_SIZE; x++) { for(int y=0; y<BLOCK_SIZE; y++) { img[i+x][j+y] = img_block[x][y]; } } } } } int main() { double img[IMAGE_SIZE][IMAGE_SIZE] = {0}; double dct[IMAGE_SIZE][IMAGE_SIZE] = {0}; /* 读取图像数据 */ /* 对整幅图像进行DCT变换 */ compress_image(img, dct); /* 对整幅图像进行逆DCT变换 */ decompress_image(dct, img); /* 输出逆DCT变换后的图像数据 */ return 0; } ``` 以上代码实现了一个简单的基于离散余弦变换图像压缩算法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值