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
27 # bits of the integer 'val'.
28 def reverse_bits(val
, width
):
30 for _
in range(width
):
31 result
= (result
<< 1) |
(val
& 1)
36 # DCT type II, unscaled. Algorithm by Byeong Gi Lee, 1984.
37 # See: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.118.3056&rep=rep1&type=pdf#page=34
38 def transform(vector
, indent
=0):
43 elif n
== 0 or n
% 2 != 0:
47 alpha
= [(vector
[i
] + vector
[-(i
+ 1)]) for i
in range(half
)]
48 beta
= [(vector
[i
] - vector
[-(i
+ 1)]) /
49 (math
.cos((i
+ 0.5) * math
.pi
/ n
) * 2.0)
51 alpha
= transform(alpha
)
52 beta
= transform(beta
)
54 for i
in range(half
- 1):
55 result
.append(alpha
[i
])
56 result
.append(beta
[i
] + beta
[i
+ 1])
57 result
.append(alpha
[-1])
58 result
.append(beta
[-1])
62 def transform(vector
, indent
=0):
67 elif n
== 0 or n
% 2 != 0:
73 print (idt
, "xf", vector
)
74 print (idt
, "coeff", n
, "->", end
=" ")
76 t1
, t2
= vector
[i
], vector
[n
-i
-1]
77 k
= (math
.cos((i
+ 0.5) * math
.pi
/ n
) * 2.0)
78 print (i
, n
-i
-1, "i/n", (i
+0.5)/n
, ":", k
, end
= " ")
80 beta
[i
] = (t1
- t2
) * (1/k
)
82 print (idt
, "n", n
, "alpha", end
=" ")
83 for i
in range(0, n
, 2):
84 print (i
, i
//2, alpha
[i
//2], end
=" ")
86 print (idt
, "n", n
, "beta", end
=" ")
87 for i
in range(0, n
, 2):
88 print (i
, beta
[i
//2], end
=" ")
90 alpha
= transform(alpha
, indent
+1)
91 beta
= transform(beta
, indent
+1)
94 result
[i
*2] = alpha
[i
]
95 result
[i
*2+1] = beta
[i
]
96 print(idt
, "merge", result
)
97 for i
in range(half
- 1):
98 result
[i
*2+1] += result
[i
*2+3]
99 print(idt
, "result", result
)
103 def transform_itersum(vector
, indent
=0):
108 elif n
== 0 or n
% 2 != 0:
114 for i
in range(half
):
115 t1
, t2
= vector
[i
], vector
[i
+half
]
118 alpha
= transform_itersum(alpha
, indent
+1)
119 beta
= transform_itersum(beta
, indent
+1)
121 for i
in range(half
):
122 result
[i
*2] = alpha
[i
]
123 result
[i
*2+1] = beta
[i
]
124 print(idt
, "iter-merge", result
)
125 for i
in range(half
- 1):
126 result
[i
*2+1] += result
[i
*2+3]
127 print(idt
, "iter-result", result
)
132 def transform2(vec
, reverse
=True):
138 print ("transform2", n
)
139 levels
= n
.bit_length() - 1
141 # reference (read/write) the in-place data in *reverse-bit-order*
144 ri
= [ri
[reverse_bits(i
, levels
)] for i
in range(n
)]
147 vec
= [vec
[reverse_bits(i
, levels
)] for i
in range(n
)]
155 tablestep
= n
// size
156 ir
= list(range(0, n
, size
))
159 j
= list(range(i
, i
+ halfsize
))
160 jr
= list(range(i
+halfsize
, i
+ size
))
162 print (" xform jr", j
, jr
)
164 for ci
, (jl
, jh
) in enumerate(zip(j
, jr
)):
165 t1
, t2
= v
[ri
[jl
]], v
[ri
[jh
]]
167 vec2
[ri
[jl
+halfsize
]] = t2
174 #vec2 = deepcopy(vec)
176 # vec[i] = vec2[v[i]]
183 tablestep
= n
// size
184 ir
= list(range(0, n
, size
))
185 print (" xform", size
, ir
)
188 j
= list(range(i
, i
+ halfsize
))
189 jr
= list(range(i
+halfsize
, i
+ size
))
191 print (" xform jr", j
, jr
)
192 for ci
, (jl
, jh
) in enumerate(zip(j
, jr
)):
193 t1
, t2
= vec
[ri
[jl
]], vec
[ri
[jh
]]
194 coeff
= (math
.cos((ci
+ 0.5) * math
.pi
/ size
) * 2.0)
195 vec
[ri
[jl
]] = t1
+ t2
196 vec
[ri
[jh
]] = (t1
- t2
) * (1/coeff
) # not jl+halfsize!
197 print ("coeff", size
, i
, k
, "jl", jl
, "jh", jh
,
198 "i/n", (k
+0.5)/size
, coeff
, vec
[ri
[jl
]], vec
[ri
[jh
]])
200 # instead of using jl+halfsize, perform a swap here.
201 # use half of j/jr because actually jl+halfsize = reverse(j)
202 # actually: swap the *indices*... not the actual data.
203 # incredibly... bizarrely... this works *without* having
204 # to do anything else.
207 for ci
, (jl
, jh
) in enumerate(zip(j
[:hz2
], jr
[:hz2
])):
208 tmp
= ri
[jl
+halfsize
]
209 ri
[jl
+halfsize
] = ri
[jh
]
211 print (" swap", size
, i
, ri
[jl
+halfsize
], ri
[jh
])
214 print("post-swapped", ri
)
215 print("transform2 pre-itersum", vec
)
221 ir
= list(range(0, halfsize
))
222 print ("itersum", halfsize
, size
, ir
)
224 jr
= list(range(i
+halfsize
, i
+n
-halfsize
, size
))
225 print ("itersum jr", i
+halfsize
, i
+size
, jr
)
227 vec
[jh
] += vec
[jh
+size
]
228 print (" itersum", size
, i
, jh
, jh
+size
)
231 print("transform2 result", vec
)
236 # DCT type III, unscaled. Algorithm by Byeong Gi Lee, 1984.
237 # See: https://www.nayuki.io/res/fast-discrete-cosine-transform-algorithms/lee-new-algo-discrete-cosine-transform.pdf
238 def inverse_transform(vector
, root
=True, indent
=0):
241 vector
= list(vector
)
246 elif n
== 0 or n
% 2 != 0:
252 for i
in range(2, n
, 2):
253 alpha
.append(vector
[i
])
254 beta
.append(vector
[i
- 1] + vector
[i
+ 1])
255 print (idt
, "n", n
, "alpha 0", end
=" ")
256 for i
in range(2, n
, 2):
258 print ("beta 1", end
=" ")
259 for i
in range(2, n
, 2):
260 print ("%d+%d" % (i
-1, i
+1), end
=" ")
262 inverse_transform(alpha
, False, indent
+1)
263 inverse_transform(beta
, False, indent
+1)
264 for i
in range(half
):
266 y
= beta
[i
] / (math
.cos((i
+ 0.5) * math
.pi
/ n
) * 2)
268 vector
[-(i
+ 1)] = x
- y
269 print (idt
, " v[%d] = alpha[%d]+beta[%d]" % (i
, i
, i
))
270 print (idt
, " v[%d] = alpha[%d]-beta[%d]" % (n
-i
-1, i
, i
))
274 def inverse_transform2(vector
, root
=True):
277 vector
= list(vector
)
280 elif n
== 0 or n
% 2 != 0:
286 for i
in range(2, n
, 2):
288 beta
.append(("add", i
- 1, i
+ 1))
289 inverse_transform2(alpha
, False)
290 inverse_transform2(beta
, False)
291 for i
in range(half
):
293 y
= ("cos", beta
[i
], i
)
294 vector
[i
] = ("add", x
, y
)
295 vector
[-(i
+ 1)] = ("sub", x
, y
)
299 def failllll_transform2(block
):
303 front
= deepcopy(block
)
304 back
= deepcopy(block
)
311 while j
> 1: #// Cycle of iterations Input Butterfly
313 current_PI_half_By_N
= (math
.pi
/ 2) / prev_half_N
314 current_PI_By_N
= 0.0
315 step_Phase
= current_PI_half_By_N
* 2.0
316 print ("n", N
, "cos", end
=" ")
317 for i
in range(half_N
):
318 #Precompute Cosine's coefficients
319 a
= current_PI_By_N
+ current_PI_half_By_N
320 print (i
, a
/ (math
.pi
), math
.cos(a
) * 2, end
=" ")
321 cos
[i
] = 0.5 / math
.cos(a
)
322 current_PI_By_N
+= step_Phase
325 for x
in range(step
):
326 for i
in range(half_N
):
327 shift
= k
+ prev_half_N
- i
- 1
328 back
[k
+ i
] = front
[k
+ i
] + front
[shift
]
329 back
[k
+ half_N
+ i
] = (front
[k
+ i
] - front
[shift
]) * cos
[i
]
330 print ("xf coeff", N
, j
, i
, x
, "k/kh", k
+i
, k
+half_N
+i
)
343 print("xform intermediate", front
)
345 while j
< N
: # Cycle of Out ButterFly
347 print ("out", j
, N
, step
, half_N
)
348 for x
in range(step
):
349 for i
in range(half_N
- 1):
350 back
[k
+ (i
<< 1)] = front
[k
+ i
]
351 back
[k
+ (i
<< 1) + 1] = (front
[k
+ half_N
+ i
] +
352 front
[k
+ half_N
+ i
+ 1])
353 print (" out", j
, x
, i
, "k", k
,
354 "k+i<<1", k
+(i
<<1), "hh1", k
+half_N
+i
)
355 back
[k
+ ((half_N
- 1) << 1)] = front
[k
+ half_N
- 1]
356 back
[k
+ (half_N
<< 1) - 1] = front
[k
+ (half_N
<< 1) - 1]
365 prev_half_N
= prev_half_N
<< 1
368 block
[i
] = front
[i
] #// Unload DCT coefficients
370 #block[0] = block[0] / dN #// Compute DC.
372 print("transform2 result", block
)
376 def itersum_explore(vector
, indent
=0):
381 elif n
== 0 or n
% 2 != 0:
387 for i
in range(half
):
388 t1
, t2
= vector
[i
], vector
[i
+half
]
391 alpha
= itersum_explore(alpha
, indent
+1)
392 beta
= itersum_explore(beta
, indent
+1)
394 for i
in range(half
):
395 result
[i
*2] = alpha
[i
]
396 result
[i
*2+1] = beta
[i
]
397 print(idt
, "iter-merge", result
)
398 for i
in range(half
- 1):
399 result
[i
*2+1] = ("add", result
[i
*2+1], result
[i
*2+3])
400 print(idt
, "iter-result", result
)
404 def itersum_explore2(vec
, indent
=0):
409 ir
= list(range(0, halfsize
))
411 print ("itersum", halfsize
, size
, ir
)
413 jr
= list(range(i
+halfsize
, i
+n
-halfsize
, size
))
414 print ("itersum jr", i
+halfsize
, i
+size
, jr
)
416 vec
[jh
] = ("add", vec
[jh
], vec
[jh
+size
])
417 print (" itersum", size
, i
, jh
, jh
+size
)
421 # vec = [vec[reverse_bits(i, levels)] for i in range(n)]
425 if __name__
== '__main__':
428 levels
= n
.bit_length() - 1
429 vec
= [vec
[reverse_bits(i
, levels
)] for i
in range(n
)]
430 ops
= itersum_explore(vec
)
431 #ops = [ops[reverse_bits(i, levels)] for i in range(n)]
432 for i
, x
in enumerate(ops
):
437 levels
= n
.bit_length() - 1
438 #vec = [vec[reverse_bits(i, levels)] for i in range(n)]
439 ops
= itersum_explore2(vec
)
440 for i
, x
in enumerate(ops
):