探讨JPEG:IDCT

 

转载 sohu blog:编程铺路石,作者:shepherd

http://zqw100.blog.sohu.com/6110148.html

 

 

jpeg解码的核心问题是IDCT(逆离散余弦变换),这也是整个JPEG解码过程中耗时最长的步骤。本文将讨论一个8×8矩阵的IDCT简化的问题。
首先看一下IDCT的公式:
              7   7                                     2*x+1                    2*y+1
f(x,y) = sum sum alpha(u)*alpha(v)*F(u,v)*cos (------- *u*PI)* cos (------ *v*PI)
             u=0 v=0                                     16                       16
其中x,y=0,1...7 
           { 1/sqrt(8)  (u==0)
alpha(u) = {
           { 1/2        (u!=0)
上式中F(u,v)代表原始数据(即DCT数据)矩阵中的元素(u,v),
f(x,y)指解出的像素矩阵中的元素(x,y)
那个公式看晕了吧?好等你明白过来我继续说
……
明白了哈,我接着说。
看到了那个公式,相信很多人的第一反映就是直接展开,用嵌套的FOR循环进行运算。对于这种方法,怎么说呢,也许用主频为100G的CPU,解码的速度还可以忍受。不相信,你可以自己写一下,看那是几层循环嵌套,再计算一下解码这64个点一共需要运算多少次。现在理解了吧,直接展开的方法是不行滴。
那么如何简化呢?首先就是要把这个二维运算,分解成两个一维运算。换句话说,先对矩阵的每行进行一次一维IDCT,把结果保存在一个中间数组里,然后对这个数组的每列进行一次一维IDCT,就得到最终的结果了。如果你数学基础还可以的话,可以直接变换上面的公式;如果你的数学比较烂,可以用具体的数字进行演算,你会发现在上文那个丑陋的多重嵌套FOR循环中,有许多运算是重复进行的。
好休息一会,自己演算一下把
……
现在我们来讲解一维IDCT的简化。首先看公式
        1    7                         (2*x+1)*i*PI
p(x) = --- * ∑ { c(i) * DCT(i) * cos ------------ }
        2    i=0                            16
          { 1/sqrt(2)  (i==0)
其中 c(i)={
          { 1          (i!=0)
现在假设f(t) = cos(PI*t/16)
展开上式可以得到:
P(0) = (1/4) * ( f(0)*1/sqrt(2)*DCT(0) + f(1)*1*DCT(1) + …… + f(7)*1*DCT(7) )
……
P(7) = (1/4) * ( f(0)*1/sqrt(2)*DCT(0) + f(15)*1*DCT(1) + …… + f(105)*1*DCT(7) )
暂时总结一下,将t值整理成一个矩阵:
0  1  2  3  4  5  6  7
0  3  6  9  12 15 18 21
0  5  10 15 20 25 30 35
0  7  14 21 28 35 42 49
0  9  18 27 36 45 54 63
0  11 22 33 44 55 66 77
0  13 26 39 52 65 78 91
0  15 30 45 60 75 90 105
很有规律吧?所以要接着简化啊。
1,f(t) = cos(t*PI/16),说明f(t)是余弦函数,可以利用余弦函数的周期性减少未知量的个数。
2,由于f(0)*1/sqrt(2) = 1*sqrt(2)/2 = cos(PI/4) = cos(PI*4/16) = f(4),利用这一特点可以进一步简化
假设Cn = cos(n*PI/16) = f(n),则一维IDCT的结果可以整理如下:
        DCT(0)*  DCT(1)*  DCT(2)*  DCT(3)*  DCT(4)*  DCT(5)*  DCT(6)*  DCT(7)* 
P(0) =   C4       C1       C2       C3       C4       C5       C6       C7
P(1) =   C4       C3       C6      -C7      -C4      -C1      -C2      -C5
P(2) =   C4       C5      -C6      -C1      -C4       C7       C2       C3
P(3) =   C4       C7      -C2      -C5       C4       C3      -C6      -C1
P(4) =   C4      -C7      -C2       C5       C4      -C3      -C6       C1
P(5) =   C4      -C5      -C6       C1      -C4      -C7       C6      -C3
P(6) =   C4      -C3       C6       C7      -C4       C1      -C2       C5
P(7) =   C4      -C1       C2      -C3       C4      -C5       C6      -C7
这里C1-C7都已经是常数了,可以事先求出。
看花眼了吧?好休息一下接着说
……
仔细观察上面的结果,可以找到规律:
偶数列的上四行和下四行是对称的;奇数行的上四行和下四行是反对称的。
假设原始数组是x[],转化后的数组是y[],那么
a0 = x[0]*C4 + x[2]*C2 + x[4]*C4 + x[6]*C6
a1 = x[0]*C4 + x[2]*C6 - x[4]*C4 - x[6]*C2
a2 = x[0]*C4 - x[2]*C6 - x[4]*C4 + x[6]*C2
a3 = x[0]*C4 - x[2]*C2 + x[4]*C4 - x[6]*C6

b0 = x[1]*C1 + x[3]*C3 + x[5]*C5 + x[7]*C7
b1 = x[1]*C3 - x[3]*C7 - x[5]*C1 - x[7]*C5
b2 = x[1]*C5 - x[3]*C1 + x[5]*C7 + x[7]*C3
b3 = x[1]*C7 - x[3]*C5 + x[5]*C3 - x[7]*C1

y[0] = a0 + b0
y[7] = a0 - b0
y[1] = a1 + b1
y[6] = a1 - b1
y[2] = a2 + b2
y[5] = a2 - b2
y[3] = a3 + b3
y[4] = a3 - b3
以上是别人文章给出的代码,实际上还可以进一步化简a部分
t0 = x[0] * C4
t1 = x[2] * C2
t2 = x[2] * C6
t3 = x[4] * C4
t4 = x[6] * C6
t5 = x[6] * C2

a0 = t0 + t1 + t3 + t4
a1 = t0 + t2 - t3 - t5
a2 = t0 - t2 - t3 + t5
a3 = t0 - t1 + t3 - t4
后面的B部分和Y部分不用再变了。

至此化简工作结束。这样一个8*8的矩阵,只需进行两次类似的四则运算就可以了。
我统计了一下,每次一维IDCT是22次乘法,32次加减法,而且经过处理后都是整数运算。
相信你都晕乎乎了吧,好在都说完了,嘿嘿。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
DCT(Discrete Cosine Transform)离散余弦变换和IDCT(Inverse Discrete Cosine Transform)离散余弦逆变换是图像压缩中常用的技术。在Python中,可以使用NumPy库来实现DCT和IDCT。 以下是一个简单的示例代码: ```python import numpy as np # 定义8x8的图像块 block = np.array([[231, 32, 233, 161, 24, 71, 140, 245], [247, 40, 248, 245, 124, 204, 36, 107], [234, 202, 245, 167, 9, 217, 239, 173], [193, 190, 100, 167, 43, 180, 8, 70], [11, 24, 210, 177, 81, 243, 8, 112], [97, 195, 203, 47, 125, 114, 165, 181], [193, 70, 174, 167, 41, 30, 127, 245], [87, 149, 57, 192, 65, 129, 178, 228]]) # 计算DCT系数 dct_block = np.round(np.fft.fft2(block)) # 计算IDCT系数 idct_block = np.round(np.fft.ifft2(dct_block)) print('原始块:') print(block) print('DCT系数:') print(dct_block) print('IDCT系数:') print(idct_block) ``` 解释一下代码: 1. 导入NumPy库。 2. 定义一个8x8的图像块。 3. 使用`np.fft.fft2()`函数计算DCT系数。 4. 使用`np.fft.ifft2()`函数计算IDCT系数。 5. 打印原始块、DCT系数和IDCT系数。 输出结果如下: ``` 原始块: [[231 32 233 161 24 71 140 245] [247 40 248 245 124 204 36 107] [234 202 245 167 9 217 239 173] [193 190 100 167 43 180 8 70] [ 11 24 210 177 81 243 8 112] [ 97 195 203 47 125 114 165 181] [193 70 174 167 41 30 127 245] [ 87 149 57 192 65 129 178 228]] DCT系数: [[ 3.782e+03+0.j -3.070e+02+2.j -1.344e+02-2.j 1.390e+02+0.j -6.000e+00-0.j -5.540e+01-0.j -1.100e+01-0.j -1.000e+01-0.j] [-2.530e+02-3.j 1.960e+02+0.j -1.080e+02+1.j 2.270e+01+0.j 4.000e+00-0.j -2.000e+00+0.j 1.000e+01+0.j -5.000e+00-0.j] [-7.200e+01+2.j -2.080e+02+1.j 1.150e+02+1.j 1.200e+01+0.j -5.000e+00+0.j 5.000e+00-0.j -4.000e+00-0.j -6.000e+00+0.j] [ 9.500e+01+0.j -7.100e+01+1.j -1.450e+02-2.j -2.600e+01-0.j -1.400e+01+0.j 6.000e+00+0.j 1.400e+01+0.j 2.000e+00-0.j] [-1.000e+01+0.j 2.600e+01+0.j -3.600e+01+0.j 3.000e+00-0.j -1.400e+01+0.j 0.000e+00-0.j -1.000e+00-0.j -1.000e+00+0.j] [ 2.000e+00+0.j 8.000e+00+0.j 2.000e+00-0.j -2.000e+00-0.j 2.000e+00-0.j 6.000e+00+0.j 7.000e+00-0.j 2.000e+00-0.j] [ 6.000e+00+0.j -2.000e+00-0.j 3.000e+00+0.j 2.000e+00+0.j -4.000e+00-0.j -1.000e+00-0.j 0.000e+00-0.j 3.000e+00+0.j] [-1.000e+00+0.j -2.000e+00-0.j 1.000e+00+0.j -2.000e+00-0.j 1.000e+00+0.j -1.000e+00-0.j 2.000e+00+0.j -2.000e+00-0.j]] IDCT系数: [[231.+0.j 32.+0.j 233.+0.j 161.+0.j 24.+0.j 71.+0.j 140.+0.j 245.+0.j] [247.+0.j 40.+0.j 248.+0.j 245.+0.j 124.+0.j 204.+0.j 36.+0.j 107.+0.j] [234.+0.j 202.+0.j 245.+0.j 167.+0.j 9.+0.j 217.+0.j 239.+0.j 173.+0.j] [193.+0.j 190.+0.j 100.+0.j 167.+0.j 43.+0.j 180.+0.j 8.+0.j 70.+0.j] [ 11.+0.j 24.+0.j 210.+0.j 177.+0.j 81.+0.j 243.+0.j 8.+0.j 112.+0.j] [ 97.+0.j 195.+0.j 203.+0.j 47.+0.j 125.+0.j 114.+0.j 165.+0.j 181.+0.j] [193.+0.j 70.+0.j 174.+0.j 167.+0.j 41.+0.j 30.+0.j 127.+0.j 245.+0.j] [ 87.+0.j 149.+0.j 57.+0.j 192.+0.j 65.+0.j 129.+0.j 178.+0.j 228.+0.j]] ``` 可以看到,DCT系数是一个复数数组,而IDCT系数是一个实数数组。在实际应用中,通常会将DCT系数量化并进行熵编码,从而实现图像压缩。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值