Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using the SciPy DCT function to create a 2D DCT-II

Tags:

scipy

I am creating a 2D DCT-II in labview but want to be able to check my outputs are correct. SciPy has a nice DCT function which defaults to DCT-II but is 1D.

I want to make it work for a 2D array. To do this the DCT must be applied to the columns and then the DCT must be again applied to the rows of this outcome.

I'm not sure what function I want to use to do this. I have tried np.rot90 which rotates the numpy array 90 degrees counter clockwise as follows:

import numpy as np
from scipy.fftpack import dct

a = np.array([[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0],
[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0],
[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0],
[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0],
[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0],
[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0],
[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0],
[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0]])

b = dct(np.rot90(dct(a),3))

However this outputs the following:

array([[ 1152.        ,     0.        ,     0.        ,     0.        ,
            0.        ,     0.        ,     0.        ,     0.        ],
       [ -412.30867345,     0.        ,     0.        ,     0.        ,
            0.        ,     0.        ,     0.        ,     0.        ],
       [    0.        ,     0.        ,     0.        ,     0.        ,
            0.        ,     0.        ,     0.        ,     0.        ],
       [  -43.10110726,     0.        ,     0.        ,     0.        ,
            0.        ,     0.        ,     0.        ,     0.        ],
       [    0.        ,     0.        ,     0.        ,     0.        ,
            0.        ,     0.        ,     0.        ,     0.        ],
       [  -12.85778584,     0.        ,     0.        ,     0.        ,
            0.        ,     0.        ,     0.        ,     0.        ],
       [    0.        ,     0.        ,     0.        ,     0.        ,
            0.        ,     0.        ,     0.        ,     0.        ],
       [   -3.24494866,     0.        ,     0.        ,     0.        ,
            0.        ,     0.        ,     0.        ,     0.        ]])

I think that rot90 is not the right function to do what I want to do, perhaps there is a better one?

like image 432
mark mcmurray Avatar asked Apr 12 '13 18:04

mark mcmurray


People also ask

What is 2d DCT?

Description. The 2-D DCT block calculates the two-dimensional discrete cosine transform of an image. Suppose f(x,y) is the input image of dimension M-by-N, the equation for the 2-D DCT is. F ( m , n ) = 2 M N C ( m ) C ( n ) ∑ x = 0 M − 1 ∑ y = 0 N − 1 f ( x , y ) cos ( 2 x + 1 ) m π 2 M cos ( 2 y + 1 ) n π 2 N.

How does Python calculate DCT?

dct() method, we can compute the discrete cosine transform by selecting different types of sequences and return the transformed array by using this method. Return value: It will return the transformed array. Example #1: In this example, we can see that by using scipy. fft.

What is DCT algorithm?

In a DCT algorithm, an image (or frame in an image sequence) is divided into square blocks which are processed independently from each other, then the DCT of these blocks is taken, and the resulting DCT coefficients are quantized. This process can cause blocking artifacts, primarily at high data compression ratios.


3 Answers

There is now a multidimensional DCT function (and inverse) as well:

>>> from scipy.fft import dctn, idctn
>>> b = dctn(a)
>>> np.allclose(a, idctn(b))
True

https://docs.scipy.org/doc/scipy/reference/generated/scipy.fft.dctn.html

like image 38
dokkaebi Avatar answered Oct 12 '22 14:10

dokkaebi


@Jaime's answer is fine. I'll add that dct has an axis argument for just this purpose. First apply it along, say, axis 0, then along axis 1 of the result:

In [30]: from scipy.fftpack import dct

In [31]: a.shape
Out[31]: (8, 8)

In [32]: t1 = dct(dct(a, axis=0), axis=1)

In [33]: t2 = dct(dct(a.T).T)

In [34]: np.abs(t1 - t2).max()
Out[34]: 0.0
like image 163
Warren Weckesser Avatar answered Oct 12 '22 14:10

Warren Weckesser


I don't think that a rotation is what you want, since it converts rows into columns, but it also messes with the order of the data. Use np.transpose instead.

To apply dct first by columns, then by rows, you would do something like:

dct(dct(a.T).T)

The trailing .T is equivalent to np.transpose. Note how you need to undo the transposition after you operate on the columns, to get the return aligned by rows again.

I don't think that the order in which you apply the dct, i.e. columns then rows vs. rows then columns, makes any difference, but you could get rows then columns as:

dct(dct(a).T).T
like image 34
Jaime Avatar answered Oct 12 '22 15:10

Jaime