图像二维整数离散余弦变换DCT 变换算法和DSP实现课程设计.docx
《图像二维整数离散余弦变换DCT 变换算法和DSP实现课程设计.docx》由会员分享,可在线阅读,更多相关《图像二维整数离散余弦变换DCT 变换算法和DSP实现课程设计.docx(16页珍藏版)》请在冰豆网上搜索。
图像二维整数离散余弦变换DCT变换算法和DSP实现课程设计
课程设计
课程名称光电图像处理综合课程设计
题目名称图像二维整数离散余弦变换
(DCT)变换算法和DSP实现
2013年11月26日
一、离散余弦变换
1、概念
离散余弦变换(DCTforDiscreteCosineTransform)是与傅里叶变换相关的一种变换,它类似于离散傅里叶变换(DFTforDiscreteFourierTransform),但是只使用实数。
离散余弦变换相当于一个长度大概是它两倍的离散傅里叶变换,这个离散傅里叶变换是对一个实偶函数进行的(因为一个实偶函数的傅里叶变换仍然是一个实偶函数),在有些变形里面需要将输入或者输出的位置移动半个单位(DCT有8种标准类型,其中4种是常见的)。
最常用的一种离散余弦变换的类型是下面给出的第二种类型,通常我们所说的离散余弦变换指的就是这种。
它的逆,也就是下面给出的第三种类型,通常相应的被称为"反离散余弦变换","逆离散余弦变换"或者"IDCT"。
有两个相关的变换,一个是离散正弦变换(DSTforDiscreteSineTransform),它相当于一个长度大概是它两倍的实奇函数的离散傅里叶变换;另一个是改进的离散余弦变换(MDCTforModifiedDiscreteCosineTransform),它相当于对交叠的数据进行离散余弦变换。
离散余弦变换,尤其是它的第二种类型,经常被信号处理和图像处理使用,用于对信号和图像(包括静止图像和运动图像)进行有损数据压缩。
这是由于离散余弦变换具有很强的"能量集中"特性:
大多数的自然信号(包括声音和图像)的能量都集中在离散余弦变换后的低频部分,而且当信号具有接近马尔科夫过程(Markovprocesses)的统计特性时,离散余弦变换的去相关性接近于K-L变换(Karhunen-Loève变换--它具有最优的去相关性)的性能。
2、离散余弦变换用于图像处理:
图像数据一般有较强的相关性,若所选用的正交矢量空间的基矢量与图像本身的主要特征相近,在该正交矢量空间中描述图像数据则会变得更简单。
经过正交变换,会把原来分散在原空间的图像数据在新的坐标空间中得到集中。
对于大多数图像,大量变换系数很小,只要删除接近于零的系数,并且对较小的系数进行粗量化,而保留包含图像主要信息的系数,以此进行压缩编码。
在重建图像进行解码时,所损失的将是一些不重要的信息,几乎不会引起图像的失真。
在变换编码中,首先要将图像数据分割成子图像,然后对子图像数据块实施某种变换,如DCT变换,那么子图像尺寸取多少好呢?
根据实践证明子图像尺寸取4×4、8×8、16×16适合作图像的压缩,这是因为:
<1>如果子图像尺寸取得太小,虽然计算速度快,实现简单,但压缩能力有一定的限制。
<2>如果子图像尺寸取得太大,虽然去相关效果变好,因为象DFT、DCT等正弦型变换均具有渐近最佳性,但也渐趋饱和。
若尺寸太大,由于图像本身的相关性很小,反而使其压缩效果不显示,而且增加了计算的复杂性。
8*8FDCT和IDCT的普通算法如下:
其中:
离散余弦变换(DiscreteCosineTranform,简称DCT)是一种与傅立叶变换紧密相关的数学运算。
在傅立叶级数展开式中,如果被展开的函数式是偶函数,那么其傅立叶级数中只包含余弦项,再将其离散化可导出余弦变换,因此称之为离散余弦变换。
时间域中信号需要许多数据点表示;在x轴表示时间,在y轴表示幅度。
信号一旦用傅立叶变换转换到频率域,就只需要几点就可以表示这个相同的信号。
如我们已经看到的那样,原因就是信号只含有少量的频率成分。
这允许在频率域中只用几个数据点就可以表示信号,而在时间域中表示则需要大量数据点。
这一技术可以应用到彩色图像上。
彩色图像有像素组成,这些像素具有RGB彩色值。
每个像素都带有x,y坐标,对每种原色使用8x8或者16x16矩阵。
在灰度图像中像素具有灰度值,它的x,y坐标由灰色的幅度组成。
为了在JPEG中压缩灰度图像,每个像素被翻译为亮度或灰度值。
为了压缩RGB彩色图像,这项工作必须进行三遍,因为JPEG分别得处理每个颜色成分,R成分第一个被压缩,然后是G成分,最后是B成分。
而一个8x8矩阵的64个值,每个值都带有各自的x,y坐标,这样我们就有了一个像素的三维表示法,称作控件表达式或空间域。
通过DCT变换,空间表达式就转化为频谱表达式或频率域。
从而到达了数据压缩的目的。
DCT式目前最佳的图像变换,它有很多优点。
DCT是正交变换,它可以将8x8图像空间表达式转换为频率域,只需要用少量的数据点表示图像;DCT产生的系数很容易被量化,因此能获得好的块压缩;DCT算法的性能很好,它有快速算法,如采用快速傅立叶变换可以进行高效的运算,因此它在硬件和软件中都容易实现;而且DCT算法是对称的,所以利用逆DCT算法可以用来解压缩图像。
为什么采用8x8的图像块,其原因是由于计算量和像素之间关系的数量,许多研究表明,在15或20个像素之后,像素间的相关性开始下降。
就是说,一列相似的像素通常会持续15到20个像素那么长,在此之后,像素就会改变幅度水平(或反向)。
模拟图像经采样后成为离散化的亮度值然后分成一个个宏块,而一个宏块有分成8x8大小的块,可以用一个矩阵来表示这个块。
在这里,N=8,矩阵中元素f(i,j)表示块中第i行、第j列像素的亮度值。
把该矩阵看作一个空间域,显然,块中这些亮度值的大小有一定的随机性,无序性,或者说亮度值的分布没有什么特征;DCT变换就是来解决这个问题的,把这些随机的数据变的有序,便于对数据进行编码压缩。
3、量化
量化过程实际上就是对DCT系数的一个优化过程。
它是利用了人眼对高频部分不敏感的特性来实现数据的大幅简化。
量化过程实际上是简单地把频率领域上每个成份,除以一个对于该成份的常数,且接着四舍五入取最接近的整数。
这是整个过程中的主要有损运算。
以这个结果来说,经常会把很多高频率的成份四舍五入而接近0,且剩下很多会变成小的正或负数。
整个量化的目的是减小非“0”系数的幅度以及增加“0”值系数的数目。
量化是图像质量下降的最主要原因。
因为人眼对亮度信号比对色差信号更敏感,因此使用了两种量化表:
亮度量化值和色差量化值。
总体上来说,DCT变换实际是空间域的低通滤波器。
对Y分量采用细量化,对UV采用粗量化。
量化表是控制JPEG压缩比的关键,这个步骤除掉了一些高频量;另一个重要原因是所有图片的点与点之间会有一个色彩过渡的过程,大量的图像信息被包含在低频率中,经过量化处理后,在高频率段,将出现大量连续的零。
二、流程图
基于DCT的图像压缩编码的程序实现的流程图如图3-1所示。
图3-1程序流程图
三、程序中实现
/************************************************************************/
/*学号:
姓名:
*/
/************************************************************************/
#include
#include
#defineN8
#definePI3.1415926
intf1[N][N]=
{
{139,144,149,153,155,155,155,155},
{144,151,153,156,159,156,156,156},
{150,155,160,163,158,156,156,156},
{159,161,162,160,160,159,159,159},
{159,160,161,162,162,155,155,155},
{161,161,161,161,160,157,157,157},
{162,162,161,163,162,157,157,157},
{162,162,161,161,163,158,158,158},
};
intq1[N][N]=//定义色度量化系数
{
{17,18,24,47,99,99,99,99},
{18,21,26,66,99,99,99,99},
{24,26,56,99,99,99,99,99},
{47,66,99,99,99,99,99,99},
{99,99,99,99,99,99,99,99},
{99,99,99,99,99,99,99,99},
{99,99,99,99,99,99,99,99},
{99,99,99,99,99,99,99,99},
};
intq2[N][N]=//定义亮度量化系数
{
{16,11,10,16,24,40,51,61},
{12,12,14,19,26,58,60,55},
{14,13,16,24,40,57,69,56},
{14,17,22,29,51,87,80,62},
{18,22,37,56,68,109,103,77},
{24,35,55,64,81,104,113,92},
{49,64,78,87,103,121,120,101},
{72,92,95,98,112,100,103,99}
};
voidshowMat_d(double**matShow);
voidshowMat_i(int**matShow);//显示函数,输出为整形数据
voidDCT(int**f,double**F);//经过FDCT变换,f为输入数据,F为输出数据
voidIDCT(int**f,int**F);//经过逆变换,f为输入数据,F为输出数据
voidquant(double**f,int**F);//量化过程,f为传进的DCT数据,F为量化后的数据
voidiQuant(int**f,int**F);//逆量化过程,f为量化后的数据,F为消除了量化的数据
voidmain()
{
doubleF[N][N]={0};//初始化输出数组
intf_1[N][N]={0};//初始化逆变换的输出数组
intf2[N][N]={0};//自定义输入数组的数据
intfq[N][N]={0};//定义量化后的数组。
intfq_1[N][N]={0};//定义经过逆变化后的数组
inti=0,j=0;
//////////////////////////////////////////////////////////////////////////
printf("输入数据f(x,y)为:
\n");
showMat_i((int**)f1);//输出原始数据
for(i=0;ifor(j=0;jf1[i][j]-=128;//减128
printf("\nDCT之后,数据F(u,v)为:
\n");
DCT((int**)f1,(double**)F);//DCT变换
showMat_d((double**)F);//输出DCT数据
quant((double**)F,(int**)fq);//量化
printf("\n量化后的DCT为:
\n");
showMat_i((int**)fq);//输出量化后的DCT数据
iQuant((int**)fq,(int**)fq_1);//经过逆量化处理
printf("\n逆量化后的数为:
\n");
showMat_i((int**)fq_1);
printf("\nIDCT之后,数据f'(x,y)为:
\n");
IDCT((int**)fq_1,(int**)f_1);//IDCT变换
for(i=0;ifor(j=0;jf_1[i][j]+=128;//加128
showMat_i((int**)f_1);//输出数据
//////////////////////////////////////////////////////////////////////////
}
voidshowMat_d(double**matShow)
{
inti=0;
intj=0;
for(i=0;i{
for(j=0;j{
printf("%5.1f",((*((double*)matShow+i*N+j))));
}
printf("\n");
}
}
voidshowMat_i(int**matShow)
{
inti=0;
intj=0;
for(i=0;i{
for(j=0;j{
printf("%3d",((*((int*)matShow+i*N+j))));
}
printf("\n");
}
}
voidquant(double**f,int**F)
{
inti=0;
intj=0;
doubletemp[N][N]={0.0};
for(i=0;ifor(j=0;j{
*((double*)temp+i*N+j)=(*((double*)f+i*N+j)/((*((int*)q2+i*N+j))));
if(((*((double*)temp+i*N+j))<0))
{
*((int*)F+i*N+j)=(int)((*((double*)temp+i*N+j))-0.5);//-0.5为四舍五入取整
}
else
*((int*)F+i*N+j)=(int)((*((double*)temp+i*N+j))+0.5);//+0.5为四舍五入取整
}
}
voidiQuant(int**f,int**F)
{
inti=0;
intj=0;
doubletemp[N][N]={0.0};
for(i=0;ifor(j=0;j{
*((double*)temp+i*N+j)=(double)*((int*)f+i*N+j)*(*((int*)q2+i*N+j));
if(((*((double*)temp+i*N+j))<0))
{
*((int*)F+i*N+j)=(int)((*((double*)temp+i*N+j))-0.5);//-0.5为四舍五入取整
}
else
*((int*)F+i*N+j)=(int)((*((double*)temp+i*N+j))+0.5);//+0.5为四舍五入取整
}
}
voidDCT(int**f,double**F)//DCT转换
{
intx,m,n;
doubledTemp[N][N]={0.0};//中间矩阵
doubletemp[N][N]={0.0};
doublecoff[N]={0.0};//变换系数
coff[0]=1/sqrt(N);
for(m=1;m{
coff[m]=sqrt
(2)/sqrt(N);
}
//一维变换,,,,对列进行一维DCT变换。
for(n=0;nfor(m=0;mfor(x=0;x(*((double*)temp+m*N+n))+=(double)(*((int*)f+x*N+n))*coff[m]*cos((2*x+1)*PI*m/(2*N));
//二维变换,,对行进行以为DCT变换
for(m=0;mfor(n=0;nfor(x=0;x}
voidIDCT(int**f,int**F)//逆变换
{
inty,m,x;
doubledTemp[N][N]={0.0};//中间矩阵
doubletemp[N][N]={0.0};
doublecoff[N]={0.0};//变换系数
coff[0]=1.0/sqrt(N);
for(m=1;m{
coff[m]=sqrt
(2)/sqrt(N);
}
//一维变换
for(x=0;xfor(y=0;yfor(m=0;m(*((double*)temp+x*N+y))+=(*((int*)f+x*N+m))*coff[m]*cos((2*y+1)*PI*m/(2*N));
//二维变换
for(y=0;yfor(x=0;x{
for(m=0;m(*((double*)dTemp+x*N+y))+=(*((double*)temp+m*N+y))*coff[m]*cos((2*x+1)*PI*m/(2*N));
if((*((double*)dTemp+x*N+y))<0)
{
(*((int*)F+x*N+y))=(int)((*((double*)dTemp+x*N+y))-0.5);//-0.5为四舍五入取整
}
else
(*((int*)F+x*N+y))=(int)((*((double*)dTemp+x*N+y))+0.5);//+0.5为四舍五入取整
}
四、输出结果
亮度量化输出结果:
色度量化结果为: