8

Cで順方向および逆方向の離散コサイン変換(DCT)を実装しようとしています。コードは、dct()関数を介してピクセルの単一の入力ブロックを変換行列に変換し、idct()を介して元のピクセル値に戻すことです。 ) 働き。添付のコードをご覧ください。idctからの出力は、244、116、244、116などの連続した値です。idct値の外観からは、プログラムが機能しているようには見えません。誰かが私を助けて、どのような結果になるかを教えてくれませんか。各関数の後に期待する必要がありますか?明らかに、idctの後、私は元の入力マトリックスにかなり近づいているはずです。

ありがとう

 # include <stdio.h>
 # define PI 3.14

void dct(float [][]);       // Function prototypes
void idct(float [][]);     // Function prototypes

void dct(float inMatrix[8][8]){

    double dct,
    Cu,
    sum,
    Cv;

    int i,
    j,
    u,
    h = 0,
    v;

    FILE * fp = fopen("mydata.csv", "w");

    float dctMatrix[8][8],
    greyLevel;                       

    for (u = 0; u < 8; ++u) {
        for (v = 0; v < 8; ++v) {

            if (u == 0) {
                Cu = 1.0 / sqrt(2.0);
            } else {
                Cu = 1.0;
            }

            if (v == 0) {
                Cv = 1.0 / sqrt(2.0);
            } else {
                Cu = (1.0);
            }   

            sum = 0.0;  

            for (i = 0; i < 8; i++) {
                for (j = 0; j < 8; j++) {

                    // Level around 0
                    greyLevel = inMatrix[i][j];

                    dct = greyLevel * cos((2 * i + 1) * u * PI / 16.0) *
                        cos((2 * j + 1) * v * PI / 16.0);

                    sum += dct;

                }               
            }
            dctMatrix[u][v] = 0.25 * Cu * Cv * sum;
            fprintf(fp, "\n %f", dctMatrix[u][v]);          
        }
        fprintf(fp, "\n");
    }  
    idct(dctMatrix);  
 }

void idct(float dctMatrix[8][8]){

    double idct,
    Cu,
    sum,
    Cv;

    int i,
    j,
    u,
    v;

    float idctMatrix[8][8],
    greyLevel;

    FILE * fp = fopen("mydata.csv", "a");

    fprintf(fp, "\n Inverse DCT");                     

    for (i = 0; i < 8; ++i) {
        for (j = 0; j < 8; ++j) { 

            sum = 0.0;  

        for (u = 0; u < 8; u++) {
            for (v = 0; v < 8; v++) {

            if (u == 0) {
                Cu = 1.0 / sqrt(2.0);
            } else {
                Cu = 1.0;
              }

            if (v == 0) {
                Cv = 1.0 / sqrt(2.0);
            } else {
                Cu = (1.0);
              }   

                    // Level around 0
                greyLevel = dctMatrix[u][v];

                idct = (greyLevel * cos((2 * i + 1) * u * PI / 16.0) *
                        cos((2 * j + 1) * v * PI / 16.0));

                sum += idct;

                }               
            }
            idctMatrix[i][j] = 0.25 * Cu * Cv * sum;
            fprintf(fp, "\n %f", idctMatrix[i][j]);         
        }
        fprintf(fp, "\n");
    }    
 }


int main() {

   float    
    testBlockA[8][8] = { {255, 255, 255, 255, 255, 255, 255, 255},
                         {255, 255, 255, 255, 255, 255, 255, 255},
                         {255, 255, 255, 255, 255, 255, 255, 255},
                         {255, 255, 255, 255, 255, 255, 255, 255},
                         {255, 255, 255, 255, 255, 255, 255, 255},
                         {255, 255, 255, 255, 255, 255, 255, 255},
                         {255, 255, 255, 255, 255, 255, 255, 255},
                         {255, 255, 255, 255, 255, 255, 255, 255} },

    testBlockB[8][8] = {{255, 0, 255, 0, 255, 0, 255, 0},
                        {0, 255, 0, 255, 0, 255, 0, 255},
                        {255, 0, 255, 0, 255, 0, 255, 0},
                        {0, 255, 0, 255, 0, 255, 0, 255},
                        {255, 0, 255, 0, 255, 0, 255, 0},
                        {0, 255, 0, 255, 0, 255, 0, 255},
                        {255, 0, 255, 0, 255, 0, 255, 0},
                        {0, 255, 0, 255, 0, 255, 0, 255} };

    dct(testBlockB);
}
4

3 に答える 3

6

There are at least two typos in the Cv constant assignment at the if statements:

    if (v == 0) {
        Cv = 1.0 / sqrt(2.0);
    } else {
        Cu = (1.0); // << this should be Cv = 1.0
    }   

Didn't check too properly though. Using the german wikipedia about cosine transform, following code works... I didn't want to spent time on figuring out how you defined what conversion constant. I guess you need to make sure that you use the correct constants and inverse functions:

#include <stdio.h>
#include <math.h>
#include <stdlib.h>

void dct(float **DCTMatrix, float **Matrix, int N, int M);
void write_mat(FILE *fp, float **testRes, int N, int M);
void idct(float **Matrix, float **DCTMatrix, int N, int M);
float **calloc_mat(int dimX, int dimY);
void free_mat(float **p);


float **calloc_mat(int dimX, int dimY){
    float **m = calloc(dimX, sizeof(float*));
    float *p = calloc(dimX*dimY, sizeof(float));
    int i;
    for(i=0; i <dimX;i++){
    m[i] = &p[i*dimY];

    }
   return m;
}

void free_mat(float **m){
  free(m[0]);
  free(m);
}

void write_mat(FILE *fp, float **m, int N, int M){

   int i, j;
   for(i =0; i< N; i++){
    fprintf(fp, "%f", m[i][0]);
    for(j = 1; j < M; j++){
       fprintf(fp, "\t%f", m[i][j]);
        }   
    fprintf(fp, "\n");
   }
   fprintf(fp, "\n");
}

void dct(float **DCTMatrix, float **Matrix, int N, int M){

    int i, j, u, v;
    for (u = 0; u < N; ++u) {
        for (v = 0; v < M; ++v) {
        DCTMatrix[u][v] = 0;
            for (i = 0; i < N; i++) {
                for (j = 0; j < M; j++) {
                    DCTMatrix[u][v] += Matrix[i][j] * cos(M_PI/((float)N)*(i+1./2.)*u)*cos(M_PI/((float)M)*(j+1./2.)*v);
                }               
            }
        }
    }  
 }

void idct(float **Matrix, float **DCTMatrix, int N, int M){
    int i, j, u, v;

    for (u = 0; u < N; ++u) {
        for (v = 0; v < M; ++v) {
          Matrix[u][v] = 1/4.*DCTMatrix[0][0];
          for(i = 1; i < N; i++){
          Matrix[u][v] += 1/2.*DCTMatrix[i][0];
           }
           for(j = 1; j < M; j++){
          Matrix[u][v] += 1/2.*DCTMatrix[0][j];
           }

           for (i = 1; i < N; i++) {
                for (j = 1; j < M; j++) {
                    Matrix[u][v] += DCTMatrix[i][j] * cos(M_PI/((float)N)*(u+1./2.)*i)*cos(M_PI/((float)M)*(v+1./2.)*j);
                }               
            }
        Matrix[u][v] *= 2./((float)N)*2./((float)M);
        }
    }  
 }



int main() {

   float    
    testBlockA[8][8] = { {255, 255, 255, 255, 255, 255, 255, 255},
                         {255, 255, 255, 255, 255, 255, 255, 255},
                         {255, 255, 255, 255, 255, 255, 255, 255},
                         {255, 255, 255, 255, 255, 255, 255, 255},
                         {255, 255, 255, 255, 255, 255, 255, 255},
                         {255, 255, 255, 255, 255, 255, 255, 255},
                         {255, 255, 255, 255, 255, 255, 255, 255},
                         {255, 255, 255, 255, 255, 255, 255, 255} },

    testBlockB[8][8] = {{255, 0, 255, 0, 255, 0, 255, 0},
                        {0, 255, 0, 255, 0, 255, 0, 255},
                        {255, 0, 255, 0, 255, 0, 255, 0},
                        {0, 255, 0, 255, 0, 255, 0, 255},
                        {255, 0, 255, 0, 255, 0, 255, 0},
                        {0, 255, 0, 255, 0, 255, 0, 255},
                        {255, 0, 255, 0, 255, 0, 255, 0},
                        {0, 255, 0, 255, 0, 255, 0, 255} };

    FILE * fp = fopen("mydata.csv", "w");
    int dimX = 8, dimY = 8;
    int i, j;

    float **testBlock = calloc_mat(dimX, dimY);
    float **testDCT = calloc_mat(dimX, dimY);
    float **testiDCT = calloc_mat(dimX, dimY);

    for(i = 0; i<dimX; i++){
      for(j = 0; j<dimY; j++){
        testBlock[i][j] = testBlockB[i][j];
      }
    }

    dct(testDCT, testBlock, dimX, dimY);
    write_mat(fp, testDCT, dimX, dimY);

    idct(testiDCT, testDCT, dimX, dimY);
    write_mat(fp, testiDCT, dimX, dimY);

    fclose(fp);
    free_mat(testBlock);
    free_mat(testDCT);
    free_mat(testiDCT);

    return 0;
}

Edit the dct is based on the crossproduct of formula DCT-II in the wiki. the idct is based on the crossproduct of formula DCT-III with the normalization factor 2/N per dimension (since this is the inverse to DCT-II as mentioned in the text). Edit I am pretty sure that the factor in the inverse dct should sqrt(2) and not 1/sqrt(2) in your version.

于 2011-11-29T13:30:57.343 に答える
2

あなたはそうしない

#include <math.h>

これは、コンパイラが数学関数について真ではないことを想定していることを意味している可能性があります。たとえば、それらはすべて を返しintます。呼び出すすべての関数はどこかで宣言する必要があることに注意してください.Cにはビルトインsin()があるよりも「ビルトイン」がありませんprintf()(もちろん、後者の場合は正しく含めますstdin.h)。

また、 をM_PI含めたら使用できます<math.h>

于 2011-11-29T12:47:26.543 に答える
1

Cv 定数 (dct() と idct() 関数の両方) のタイプミスに関する以前の回答に加えて、逆 DCT 式 (2 番目)を 間違って使用しました。ループのたびに Cv と Cu を乗算する必要がありました。したがって、idct() の正しいコードは次のようになります。

void idct(float dctMatrix[8][8]){

    double idct,
    Cu,
    sum,
    Cv;

    int i,
    j,
    u,
    v;

    float idctMatrix[8][8],
    greyLevel;

    FILE * fp = fopen("mydata.csv", "a");
    fprintf(fp, "\n Inverse DCT");      

    for (i = 0; i < 8; ++i) {
        for (j = 0; j < 8; ++j) { 

            sum = 0.0;  

        for (u = 0; u < 8; u++) {
            for (v = 0; v < 8; v++) {

            if (u == 0) {
                Cu = 1.0 / sqrt(2.0);
            } else {
                Cu = 1.0;
              }

            if (v == 0) {
                Cv = 1.0 / sqrt(2.0);
            } else {
                Cv = (1.0); //mistake was here - the same is in dct()
              }   
                greyLevel = dctMatrix[u][v];

                 // Multiply by Cv and Cu here!
                idct = (greyLevel * Cu * Cv *          
                        cos((2 * i + 1) * u * PI / 16.0) *
                        cos((2 * j + 1) * v * PI / 16.0));

                sum += idct;
                }               
            }
            // not "* Cv * Cu" here!
            idctMatrix[i][j] = 0.25 * sum;           
            fprintf(fp, "\n %f", idctMatrix[i][j]);  
        }
        fprintf(fp, "\n");      
    }    
 }

この場合、出力値は 255、0、255、0 などに近くなります。

于 2016-09-01T09:37:34.180 に答える