2010-11-21 22 views
5

Ici, j'ai ma classe d'algorithme DCT avec les méthodes "applyDCT" et "applyIDCT". Techniquement, après avoir fait une DCT directe (transformée en cosinus discrète) sur une table 2x2 d'entiers aléatoires entre 0 et 255, puis en effectuant immédiatement une DCT inverse sur ces nombres, nous devrions revenir aux nombres entiers originaux que nous avions en premier lieu. Dans mon cas, ce n'est pas le cas. Qu'est-ce que je fais mal ici?Problèmes avec l'algorithme DCT et IDCT dans java

public class DCT { 
    private static final int N = 2; 
    private double[] c = new double[N]; 

    public DCT() { 
      this.initializeCoefficients(); 
    } 

    private void initializeCoefficients() { 
     for (int i=1;i<N;i++) { 
      c[i]=1; 
     } 
     c[0]=1/Math.sqrt(2.0); 
    } 

    public double[][] applyDCT(double[][] f) { 
     double[][] F = new double[N][N]; 
     for (int u=0;u<N;u++) { 
      for (int v=0;v<N;v++) { 
      double sum = 0.0; 
      for (int i=0;i<N;i++) { 
       for (int j=0;j<N;j++) { 
       sum+=Math.cos(((2*i+1)/(2.0*N))*u*Math.PI)*Math.cos(((2*j+1)/(2.0*N))*v*Math.PI)*f[i][j]; 
       } 
      } 
      sum*=((c[u]*c[v])/4.0); 
      F[u][v]=sum; 
      } 
     } 
     return F; 
    } 

    public double[][] applyIDCT(double[][] F) { 
     double[][] f = new double[N][N]; 
     for (int u=0;u<N;u++) { 
      for (int v=0;v<N;v++) { 
      double sum = 0.0; 
      for (int i=0;i<N;i++) { 
       for (int j=0;j<N;j++) { 
       sum+=((c[u]*c[v]))*Math.cos(((2*i+1)/(2.0*N))*u*Math.PI)*Math.cos(((2*j+1)/(2.0*N))*v*Math.PI)*F[i][j]; 
       } 
      } 
      sum/=4.0; 
      //sum*=((c[u]*c[v])/4.0); 
      f[u][v]=sum; 
      } 
     } 
     return f; 
    } 
} 

Et voici la classe principale qui va avec:

public class Main { 
    private static final int N = 2; 
    private static double[][] f = new double[N][N]; 
    private static Random generator = new Random(); 

    public static void main(String[] args) { 
     // Generate random integers between 0 and 255 
     int value; 
     for (int x=0;x<N;x++) { 
      for (int y=0;y<N;y++) { 
       value = generator.nextInt(255); 
       f[x][y] = value; 
       System.out.println(f[x][y]+" => f["+x+"]["+y+"]"); 
      } 
     } 

     DCT dctApplied = new DCT(); 
     double[][] F = dctApplied.applyDCT(f); 
     System.out.println("From f to F"); 
     System.out.println("-----------"); 
     for (int x=0;x<N;x++) { 
      for (int y=0;y<N;y++) { 
      try { 
       System.out.println(F[x][y]+" => F["+x+"]["+y+"]"); 
       } catch (Exception e) { 
        System.out.println(e); 
       } 
      } 
     } 

     double f[][] = dctApplied.applyIDCT(F); 
     System.out.println("Back to f"); 
     System.out.println("---------"); 
     for (int y=0;y<N;y++) { 
      for (int z=0;z<N;z++) { 
       System.out.println(f[y][z]+" => f["+y+"]["+z+"]"); 
      } 
     } 
    } 
} 

Voici par exemple des résultats:

149.0 => f[0][0] 
237.0 => f[0][1] 
122.0 => f[1][0] 
147.0 => f[1][1] 

From f to F 
----------- 
81.87499999999999 => F[0][0] 
-14.124999999999993 => F[0][1] 
14.62500000000001 => F[1][0] 
-7.875 => F[1][1] 

Back to f 
--------- 
9.3125 => f[0][0] 
14.812499999999998 => f[0][1] 
7.624999999999999 => f[1][0] 
9.187499999999998 => f[1][1] 

Comme indiqué ci-dessus, "Retour à f" ne montre pas les mêmes valeurs contenues dans f initialement ...

+2

Quel a été le cas d'entrée, ce qui était le résultat attendu, et ce que le résultat réel? Avez-vous essayé d'exécuter chacune de vos routines sur des cas d'entrée triviaux (par exemple, [1 0; 0 0]) pour savoir lequel était incorrect? –

+0

Quels résultats obtenez-vous lorsque vous dites que vous ne récupérez pas vos entiers originaux? Certaines erreurs d'arrondi à virgule flottante peuvent être introduites. – rsp

+0

DCT lui-même est lossy. Vous avez besoin d'un DCT modifié (DCT sans perte) pour obtenir un fonctionnement sans perte (réversible). – osgx

Répondre

8

J'ai résolu ce problème, je suis désolé si ma question n'était pas claire mais elle e est ce qui n'a pas droit: La méthode IDCT devait avoir le coefficient intérieur du i et j pour les boucles:

public double[][] applyIDCT(double[][] F) { 
     double[][] f = new double[N][N]; 
     for (int i=0;i<N;i++) { 
      for (int j=0;j<N;j++) { 
      double sum = 0.0; 
      for (int u=0;u<N;u++) { 
       for (int v=0;v<N;v++) { 
       sum+=(c[u]*c[v])/4.0*Math.cos(((2*i+1)/(2.0*N))*u*Math.PI)*Math.cos(((2*j+1)/(2.0*N))*v*Math.PI)*F[u][v]; 
       } 
      } 
      f[i][j]=Math.round(sum); 
      } 
     } 
     return f; 
    } 

Cela ne fonctionne que pour un bloc 8x8 de données, ou bien vous devez changer ceci:

(c[u]*c[v])/4.0) 

en quelque chose comme ceci:

(2*c[u]*c[v])/Math.sqrt(M*N) 

M et N sont les dimentions de la table ...

Voici les résultats avec un bloc 2x2 de données:

Original values 
--------------- 
54.0 => f[0][0] 
35.0 => f[0][1] 
128.0 => f[1][0] 
185.0 => f[1][1] 

From f to F 
----------- 
200.99999999999994 => F[0][0] 
-18.99999999999997 => F[0][1] 
-111.99999999999997 => F[1][0] 
37.99999999999999 => F[1][1] 

Back to f 
--------- 
54.0 => f[0][0] 
35.0 => f[0][1] 
128.0 => f[1][0] 
185.0 => f[1][1]