可以将二维变换分解成一系列一维变换(行,列)进行计算。即
1(2j?1)u???7F?u,v???C?u???G?i,v?cos?
216?i?0?1(2j?1)v???7 F?u,v???C?v???f?i,j?cos?216?i?0?两维DCT变换分解为一维的DCT变换示意如图2-4所示。
图2.4 二维的DCT变换分解为一维的DCT变换
以灰度图像为例,首先将图像分解维8×8的像素块,由块的灰度值的8×8矩阵表示。对这个8×8块进行离散余弦变换,就产生了DCT系统。表2-1给出了一个带有像素值的图像。表中的数字代表了8×8矩阵中的每个像素的灰度幅度。它是矩阵的空间域表示。表2-2列出了由前面所示的公式产生了DCT系数之后的同一个8×8输出矩阵。
表2-1 DCT系数输入矩阵
132 136 140 144 150 144 150 148 136 140 143 144 152 145 156 145 138 140 144 146 155 146 157 146 140 147 148 145 156 148 156 148 144 140 150 149 150 143 140 156 145 148 152 150 145 158 146 160 147 155 154 153 144 150 156 140 155 156 155 160 140 140 145 145 表2-2 DCT系数的输出矩阵
132 136 140
136 140 143 138 140 144 140 147 148 9
144 140 150 145 148 152 147 155 154 155 156 155 144 150 144 150 148 144 152 145 156 145 146 155 146 157 146 145 156 148 156 148 149 150 143 140 156 150 145 158 146 160 153 144 150 156 140 160 140 140 145 145 输出矩阵表示的是频率域。矩阵中的第0行0列具有DCT系数为172,这一系数比其他63个系数大很多。称它作DC系数,因为它表示了8×8输入矩阵全部值的平均数,其余63个系数称为AC系数。并且,如输出矩阵所示,AC系数的值随着它与DC系数的距离增加而越来越小。从这个例子我们可以得出结论:DCT将8×8图像块变换成频率域时数值集中在矩阵左上角。即8×8的图像经过DCT变换后,其低频分量都集中在左上角,高频分量分布在右下角(DCT变换实际上是空间域的低通滤波器)。由于该低频分量包含了图像的主要信息(如亮度),而高频与之相比就不那么重要了,所以我们可以忽略高频分量,从而达到压缩的目的。这样就减少了数据量,因为在定义整个矩阵时,只有其中一小部分的值是真正有用的。[3]
很明显,如果我们删除一些离DC系数较远的值,就会损失一些信息。但是,正如我们一直所说的,人眼能够推知信息,预期的那样在大部分情况下人眼能推知或感觉不到丢失的信息。
下面给出正向DCT变换的算法代码,由于采用的是浮点运算,因此它的运算是比较准确的,但是它的精度会受到量化精度的影响。
/*
* jfdctflt.c
*该文件为前向DCT的浮点运算,它要比整数运算更精确。 */
#ifdef DCT_FLOAT_SUPPORTED /*该程序只适用于8×8的块变换*/ #if DCTSIZE != 8
Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ #endif
/* 在一个采样块上进行DCT变换 */ GLOBAL(void)
10
jpeg_fdct_float (FAST_FLOAT * data) {
FAST_FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; FAST_FLOAT tmp10, tmp11, tmp12, tmp13; FAST_FLOAT z1, z2, z3, z4, z5, z11, z13; FAST_FLOAT *dataptr; int ctr;
/* 第一部分,对行进行计算 */ dataptr = data;
for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { tmp0 = dataptr[0] + dataptr[7]; tmp7 = dataptr[0] - dataptr[7]; tmp1 = dataptr[1] + dataptr[6]; tmp6 = dataptr[1] - dataptr[6]; tmp2 = dataptr[2] + dataptr[5]; tmp5 = dataptr[2] - dataptr[5]; tmp3 = dataptr[3] + dataptr[4]; tmp4 = dataptr[3] - dataptr[4]; /* 对偶数项进行运算 */
tmp10 = tmp0 + tmp3; /* phase 2 */ tmp13 = tmp0 - tmp3; tmp11 = tmp1 + tmp2; tmp12 = tmp1 - tmp2;
dataptr[0] = tmp10 + tmp11; /* phase 3 */ dataptr[4] = tmp10 - tmp11;
z1 = (tmp12 + tmp13) * ((FAST_FLOAT) 0.707106781); /* c4 */ dataptr[2] = tmp13 + z1; /* phase 5 */ dataptr[6] = tmp13 - z1; /* 对奇数项进行计算 */
tmp10 = tmp4 + tmp5; /* phase 2 */
11
tmp11 = tmp5 + tmp6; tmp12 = tmp6 + tmp7;
z5 = (tmp10 - tmp12) * ((FAST_FLOAT) 0.382683433); /* c6 */ z2 = ((FAST_FLOAT) 0.541196100) * tmp10 + z5; /* c2-c6 */ z4 = ((FAST_FLOAT) 1.306562965) * tmp12 + z5; /* c2+c6 */ z3 = tmp11 * ((FAST_FLOAT) 0.707106781); /* c4 */ z11 = tmp7 + z3; z13 = tmp7 - z3; dataptr[5] = z13 + z2; dataptr[3] = z13 - z2; dataptr[1] = z11 + z4; dataptr[7] = z11 - z4;
dataptr += DCTSIZE; /* 将指针指向下一行 */ }
/* 第二部分,对列进行计算 */ dataptr = data;
for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7]; tmp7 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7]; tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6]; tmp6 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6]; tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5]; tmp5 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5]; tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4]; tmp4 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4]; /* 对偶数项进行运算 */
tmp10 = tmp0 + tmp3; /* phase 2 */ tmp13 = tmp0 - tmp3; tmp11 = tmp1 + tmp2; tmp12 = tmp1 - tmp2;
12
/* phase 5 */
/* phase 6 */
dataptr[DCTSIZE*0] = tmp10 + tmp11; /* phase 3 */ dataptr[DCTSIZE*4] = tmp10 - tmp11;
z1 = (tmp12 + tmp13) * ((FAST_FLOAT) 0.707106781); /* c4 */ dataptr[DCTSIZE*2] = tmp13 + z1; /* phase 5 */ dataptr[DCTSIZE*6] = tmp13 - z1; /* 对奇数项进行计算 */
tmp10 = tmp4 + tmp5; /* phase 2 */ tmp11 = tmp5 + tmp6; tmp12 = tmp6 + tmp7;
z5 = (tmp10 - tmp12) * ((FAST_FLOAT) 0.382683433); /* c6 */ z2 = ((FAST_FLOAT) 0.541196100) * tmp10 + z5; /* c2-c6 */ z4 = ((FAST_FLOAT) 1.306562965) * tmp12 + z5; /* c2+c6 */ z3 = tmp11 * ((FAST_FLOAT) 0.707106781); /* c4 */ z11 = tmp7 + z3; z13 = tmp7 - z3;
dataptr[DCTSIZE*5] = z13 + z2; /* phase 6 */ dataptr[DCTSIZE*3] = z13 - z2; dataptr[DCTSIZE*1] = z11 + z4; dataptr[DCTSIZE*7] = z11 - z4; dataptr++; }
#endif /* DCT_FLOAT_SUPPORTED */
2.4. 熵编码
熵是热力学中的术语,用来研究热和功。只要物体具备的做功能量下降,它的量就增加。熵也用来衡量物体内部的无序程度。而在信息论中,熵表示的是不确定性的量度。 2.4.1. 熵
在日常生活中,如果收到一封信,接到一个传真,或者得到一组数据,从信息论的观点看,只能称之为“消息”(Message)。在消息中,有一些是我们事先所不确定的,这些不确定的内容称为“信息”(Information)。在收到消息之前,是处于某种不确定状态
13
/* phase 5 */
/* 将指针指向下一列 */