2 # Fast discrete cosine transform algorithms (Python)
4 # Copyright (c) 2020 Project Nayuki. (MIT License)
5 # https://www.nayuki.io/page/fast-discrete-cosine-transform-algorithms
7 # Permission is hereby granted, free of charge, to any person obtaining a copy of
8 # this software and associated documentation files (the "Software"), to deal in
9 # the Software without restriction, including without limitation the rights to
10 # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11 # the Software, and to permit persons to whom the Software is furnished to do so,
12 # subject to the following conditions:
13 # - The above copyright notice and this permission notice shall be included in
14 # all copies or substantial portions of the Software.
15 # - The Software is provided "as is", without warranty of any kind, express or
16 # implied, including but not limited to the warranties of merchantability,
17 # fitness for a particular purpose and noninfringement. In no event shall the
18 # authors or copyright holders be liable for any claim, damages or other
19 # liability, whether in an action of contract, tort or otherwise, arising from,
20 # out of or in connection with the Software or the use or other dealings in the
25 from copy
import deepcopy
28 # DCT type II, unscaled. Algorithm by Byeong Gi Lee, 1984.
29 # See: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.118.3056&rep=rep1&type=pdf#page=34
30 def transform(vector
, indent
=0):
35 elif n
== 0 or n
% 2 != 0:
39 alpha
= [(vector
[i
] + vector
[-(i
+ 1)]) for i
in range(half
)]
40 beta
= [(vector
[i
] - vector
[-(i
+ 1)]) /
41 (math
.cos((i
+ 0.5) * math
.pi
/ n
) * 2.0)
43 alpha
= transform(alpha
)
44 beta
= transform(beta
)
46 for i
in range(half
- 1):
47 result
.append(alpha
[i
])
48 result
.append(beta
[i
] + beta
[i
+ 1])
49 result
.append(alpha
[-1])
50 result
.append(beta
[-1])
54 def transform(vector
, indent
=0):
59 elif n
== 0 or n
% 2 != 0:
65 print (idt
, "xf", vector
)
66 print (idt
, "coeff", n
, "->", end
=" ")
68 t1
, t2
= vector
[i
], vector
[n
-i
-1]
69 k
= (math
.cos((i
+ 0.5) * math
.pi
/ n
) * 2.0)
70 print (i
, n
-i
-1, "i/n", (i
+0.5)/n
, ":", k
, end
= " ")
72 beta
[i
] = (t1
- t2
) * (1/k
)
74 print (idt
, "n", n
, "alpha", end
=" ")
75 for i
in range(0, n
, 2):
76 print (i
, i
//2, alpha
[i
//2], end
=" ")
78 print (idt
, "n", n
, "beta", end
=" ")
79 for i
in range(0, n
, 2):
80 print (i
, beta
[i
//2], end
=" ")
82 alpha
= transform(alpha
, indent
+1)
83 beta
= transform(beta
, indent
+1)
86 result
[i
*2] = alpha
[i
]
87 result
[i
*2+1] = beta
[i
]
88 print(idt
, "merge", result
)
89 for i
in range(half
- 1):
90 result
[i
*2+1] += result
[i
*2+3]
91 print(idt
, "result", result
)
95 def transform_itersum(vector
, indent
=0):
100 elif n
== 0 or n
% 2 != 0:
106 for i
in range(half
):
107 t1
, t2
= vector
[i
], vector
[i
+half
]
110 alpha
= transform_itersum(alpha
, indent
+1)
111 beta
= transform_itersum(beta
, indent
+1)
113 for i
in range(half
):
114 result
[i
*2] = alpha
[i
]
115 result
[i
*2+1] = beta
[i
]
116 print(idt
, "iter-merge", result
)
117 for i
in range(half
- 1):
118 result
[i
*2+1] += result
[i
*2+3]
119 print(idt
, "iter-result", result
)
124 def transform2(vec
, reverse
=True):
127 # bits of the integer 'val'.
128 def reverse_bits(val
, width
):
130 for _
in range(width
):
131 result
= (result
<< 1) |
(val
& 1)
137 print ("transform2", n
)
138 levels
= n
.bit_length() - 1
143 tablestep
= n
// size
144 ir
= list(range(0, n
, size
))
145 print (" xform", size
, ir
)
148 j
= list(range(i
, i
+ halfsize
))
149 jr
= list(range(i
+halfsize
, i
+ size
))
151 print (" xform jr", j
, jr
)
153 for ci
, (jl
, jh
) in enumerate(zip(j
, jr
)):
154 # exact same actual computation, just embedded in
155 # triple-nested for-loops
156 t1
, t2
= vec
[jl
], vec
[jh
]
157 coeff
= (math
.cos((ci
+ 0.5) * math
.pi
/ size
) * 2.0)
159 vec2
[jl
+halfsize
] = (t1
- t2
) * (1/coeff
)
160 print ("coeff", size
, i
, k
, "jl", jl
, "jh", jh
,
161 "i/n", (k
+0.5)/size
, coeff
, vec
[jl
], vec
[jh
])
167 print("transform2 pre-itersum", vec
)
168 # Copy with bit-reversed permutation
171 vec
= transform_itersum(vec
)
172 print("transform2 intermediate", vec
)
178 tablestep
= n
// size
179 ir
= list(range(0, n
, size
))
181 print ("itersum", size
, ir
)
183 jr
= list(range(i
+halfsize
, i
+ size
-1))
185 print ("itersum jr", jr
)
187 # exact same actual computation, just embedded in
188 # triple-nested for-loops
191 print (" itersum", size
, i
, j
, jh
, jh
+1)
195 vec
= [vec
[reverse_bits(i
, levels
)] for i
in range(n
)]
197 print("transform2 result", vec
)
202 # DCT type III, unscaled. Algorithm by Byeong Gi Lee, 1984.
203 # See: https://www.nayuki.io/res/fast-discrete-cosine-transform-algorithms/lee-new-algo-discrete-cosine-transform.pdf
204 def inverse_transform(vector
, root
=True, indent
=0):
207 vector
= list(vector
)
212 elif n
== 0 or n
% 2 != 0:
218 for i
in range(2, n
, 2):
219 alpha
.append(vector
[i
])
220 beta
.append(vector
[i
- 1] + vector
[i
+ 1])
221 print (idt
, "n", n
, "alpha 0", end
=" ")
222 for i
in range(2, n
, 2):
224 print ("beta 1", end
=" ")
225 for i
in range(2, n
, 2):
226 print ("%d+%d" % (i
-1, i
+1), end
=" ")
228 inverse_transform(alpha
, False, indent
+1)
229 inverse_transform(beta
, False, indent
+1)
230 for i
in range(half
):
232 y
= beta
[i
] / (math
.cos((i
+ 0.5) * math
.pi
/ n
) * 2)
234 vector
[-(i
+ 1)] = x
- y
235 print (idt
, " v[%d] = alpha[%d]+beta[%d]" % (i
, i
, i
))
236 print (idt
, " v[%d] = alpha[%d]-beta[%d]" % (n
-i
-1, i
, i
))
240 def inverse_transform2(vector
, root
=True):
243 vector
= list(vector
)
246 elif n
== 0 or n
% 2 != 0:
252 for i
in range(2, n
, 2):
254 beta
.append(("add", i
- 1, i
+ 1))
255 inverse_transform2(alpha
, False)
256 inverse_transform2(beta
, False)
257 for i
in range(half
):
259 y
= ("cos", beta
[i
], i
)
260 vector
[i
] = ("add", x
, y
)
261 vector
[-(i
+ 1)] = ("sub", x
, y
)
265 def failllll_transform2(block
):
269 front
= deepcopy(block
)
270 back
= deepcopy(block
)
277 while j
> 1: #// Cycle of iterations Input Butterfly
279 current_PI_half_By_N
= (math
.pi
/ 2) / prev_half_N
280 current_PI_By_N
= 0.0
281 step_Phase
= current_PI_half_By_N
* 2.0
282 print ("n", N
, "cos", end
=" ")
283 for i
in range(half_N
):
284 #Precompute Cosine's coefficients
285 a
= current_PI_By_N
+ current_PI_half_By_N
286 print (i
, a
/ (math
.pi
), math
.cos(a
) * 2, end
=" ")
287 cos
[i
] = 0.5 / math
.cos(a
)
288 current_PI_By_N
+= step_Phase
291 for x
in range(step
):
292 for i
in range(half_N
):
293 shift
= k
+ prev_half_N
- i
- 1
294 back
[k
+ i
] = front
[k
+ i
] + front
[shift
]
295 back
[k
+ half_N
+ i
] = (front
[k
+ i
] - front
[shift
]) * cos
[i
]
296 print ("xf coeff", N
, j
, i
, x
, "k/kh", k
+i
, k
+half_N
+i
)
309 print("xform intermediate", front
)
311 while j
< N
: # Cycle of Out ButterFly
313 print ("out", j
, N
, step
, half_N
)
314 for x
in range(step
):
315 for i
in range(half_N
- 1):
316 back
[k
+ (i
<< 1)] = front
[k
+ i
]
317 back
[k
+ (i
<< 1) + 1] = (front
[k
+ half_N
+ i
] +
318 front
[k
+ half_N
+ i
+ 1])
319 print (" out", j
, x
, i
, "k", k
,
320 "k+i<<1", k
+(i
<<1), "hh1", k
+half_N
+i
)
321 back
[k
+ ((half_N
- 1) << 1)] = front
[k
+ half_N
- 1]
322 back
[k
+ (half_N
<< 1) - 1] = front
[k
+ (half_N
<< 1) - 1]
331 prev_half_N
= prev_half_N
<< 1
334 block
[i
] = front
[i
] #// Unload DCT coefficients
336 #block[0] = block[0] / dN #// Compute DC.
338 print("transform2 result", block
)
342 if __name__
== '__main__':
344 ops
= inverse_transform(vector
)