Search code examples
cdct

How does this 2D DCT code actually work?


Here is the code:

void dct(const tga_image *tga, double data[8][8],
    const int xpos, const int ypos)
{
    int i,j;
    double in[8], out[8], rows[8][8];

    /* transform rows */
    for (j=0; j<8; j++)
    {
        for (i=0; i<8; i++)
            in[i] = (double) pixel(tga, xpos+i, ypos+j);
        dct_1d(in, out, 8);
        for (i=0; i<8; i++) rows[j][i] = out[i];
    }

    /* transform columns */
    for (j=0; j<8; j++)
    {
        for (i=0; i<8; i++)
            in[i] = rows[i][j];
        dct_1d(in, out, 8);
        for (i=0; i<8; i++) data[i][j] = out[i];
    }
}

It is taken from listing2.c found at https://unix4lyfe.org/dct/

I have just 1 question, we fill in rows as rows[j][i] but then read it out rows[i][j]. As per the 2D DCT formula we transpose the DCT matrix and not the actual data. Why is the actual data being transposed?


Solution

  • If I assume xpos as horizontal index and ypos as vertical index, then the following is true.

    The function dct_1d(*,*,*); works on only 1-d arrays (here in and out). What you are getting carried away by is due to the indexing jugglery for 2d arrays in C here (in particular rows here).

    By a simple swap of variables i and j in the first for block, the same code can be rewritten as follows which will make physical sense as you are trying (see the comments):

    void dct(const tga_image *tga, double data[8][8],
        const int xpos, const int ypos)
    {
        int i,j; /* as in matrix[i][j] */
        double in[8], out[8], rows[8][8];
    
        /* transform rows (each is running horizontally with j) */
        for (i=0; i<8; i++)
        {
            for (j=0; j<8; j++)
                in[j] = (double) pixel(tga, xpos+j, ypos+i); /* fill current row i */
            /* Note above xpos in an image is horizontal as j is in a matrix[i][j] in c and
            vice versa. (The fallacy that you will make is the following: You will think that 
            xpos corresponds to i and ypos corresponds to j, which is incorrect.) */
            dct_1d(in, out, 8); /* transform current row i */
            for (j=0; j<8; j++) rows[i][j] = out[j]; /* copy back current row i */
        }
    
        /* transform columns  (each is running vertically with i) */
        for (j=0; j<8; j++)
        {
            for (i=0; i<8; i++)
                in[i] = rows[i][j]; /* fill current column j */
            dct_1d(in, out, 8); /* transform current column j */
            for (i=0; i<8; i++) data[i][j] = out[i]; /* copy back current column j */
        }
    }