[最终话]最惊心动魄的单元了,IDCT变换。近代图像处理技术的灵魂。本作可使用两种算法。AA&N和LLM算法。其中LLM算法的代码是在网站上找来的,仅可供教学用途。AA&N算法是偶整理的(当然,还是免不了参考别人的代码。)
介于各网站上基本都是抄来的文章,没有详细讲解的,偶就多写一点了。偶数学也不好,花了很多时间来学,理解上可能还是有不少问题,还请多包涵了^^b。
DCT算法是一个矩阵的乘法运算,并且是可逆的。因此,正向变换和反向变换可使用非常类似的算法。
JPEG的发明者曾经在FFT和DCT之间做出取舍,最终选择了DCT,是因为它有很多快速算法。
其基本的优化是,将8*8矩阵的乘法分解成两次矩阵乘法(即人们常说的二维IDCT分解为两次一维IDCT)。公式如下:
Z = AXA(t)
其中A(t)表示A的转置。
X是8*8的输入矩阵。这样,计算起来,就先对X的每一列和A的行进行计算,结果是一列,然后这一列再和A(t)的相对应行进行计算,结果又成为一行。由于每一列或一行的的每一个元素计算包括8次乘法和7次加法,所以一共有8*8*8*2次乘法和7*8*8*2次加法。(大概是这么多,偶数学也不咋滴-___-b)
然后,一维DCT还可以进一步优化,分为奇数列/行和偶数列/行:
/ Y[0] / / a c a f / / X[0] / / b d e g / / X[1] /
| Y[1] | = | a f -a -c | | X[2] | + | d -g -b -e | | X[3] |
| Y[2] | | a -f -a c | | X[4] | | e -b g d | | X[5] |
/ Y[3] / / a -c a -f / / X[6] / / g -e d -b / / X[7] /
/ Y[7] / / a c a f / / X[0] / / b d e g / / X[1] /
| Y[6] | = | a f -a -c | | X[2] | - | d -g -b -e | | X[3] |
| Y[5] | | a -f -a c | | X[4] | | e -b g d | | X[5] |
/ Y[4] / / a -c a -f / / X[6] / / g -e d -b / / X[7] /
其中Y[0]-Y[7]都是1*8的矩阵,X[1]-X[7]也都是1*8的矩阵。
{a, b, c, d, e, f, g} = 1/2 { cos(pi/4), cos(pi/16), cos(pi/8), cos(3pi/16), cos(5pi/16), cos(3pi/8), cos(7pi/16) }
在这之后的优化算法,就是各有千秋了,比较著名的有ChenDCT,LeeDCT,AA&N算法和LLM算法。其中AA&N算法只需要29次加法和5次乘法。(注意,它是指每次一维运算要29次加法和5次乘法,一共是需要29*8*2次加法和5*8*2次乘法的)。但它的条件是要对输入的矩阵首先各乘以一个因子。因为在矩阵从哈夫曼解开后,是游程码,游程码解开后,要进行反量化,这一次乘法是省不了的,所以把因子先乘到量化表上,就可以省去这些时间了(2007/1/26: 原来写成4次了,经Mr.Chen提醒现改正)。
本作因考虑移植性,使用的AA&N算法是整数算法,对小数进行了乘以256的操作。本作中的任何地方都不会用到浮点数。
LLM算法的速度和AA&N差不多(可能是偶写得太差了?-___-b)
jpegidct.h(这个头文件需要包含,以下两个c文件只能任选一个加到工程中。)
************************************************************************************************************
/**************************************************************************************************
superarhow's JPEG decoder
by superarhow(superarhow@hotmail.com). All rights reserved.
**************************************************************************************************/
#pragma once
#include "jpegdec2.h"
/* 2D-IDCT 变换 */
void jpeg_idct( p_jpeg_quality_table p_table, SHORT* in );
void jpeg_idct_prepare_qualitytable( p_jpeg_quality_table p_table );
*******************************************************************************************************
jpegidct.c(AA&N算法)
********************************************************************************************************
#include "jpegidct.h"
#include "memory.h"
/*
* AA&N reverse-dct arithmetic implemention
* {a, b, c, d, e, f, g} = 1/2 { cos(pi/4), cos(pi/16), cos(pi/8), cos(3pi/16), cos(5pi/16), cos(3pi/8), cos(7pi/16) }
* if we let: (out[8][8] is the temporary place to hold our first 1D-DCT data)
* X[0] = ( in[0, 0], in[1, 0], in[2, 0] ... in[7, 0] )
* X[1] = ( in[0, 1], in[1, 1], in[2, 1] ... in[7, 1] )
* ...
* X[7] = ( in[0, 7], in[1, 7], in[2, 7] ... in[7, 7] )
* Y[0] = ( out[0, 0], out[1, 0], out[2, 0] ... out[7, 0] )
* Y[1] = ( out[0, 1], out[1, 1], out[2, 1] ... out[7, 1] )
* ...
* Y[7] = ( out[0, 7], out[1, 7], out[2, 7] ... out[7, 7] )
* we'll have:
*
* / Y[0] / / a c a f / / X[0] / / b d e g / / X[1] /
* | Y[1] | &