2010-11-21 4 views
5

Qui ho la mia classe dell'algoritmo DCT con i metodi "applyDCT" e "applyIDCT". Tecnicamente dopo aver eseguito un DCT (discrete cosine transform) in avanti su una tabella 2x2 di numeri interi casuali tra 0 e 255, e quindi facendo immediatamente un DCT inverso su questi numeri, dovremmo tornare ai numeri interi originali che avevamo in primo luogo. Nel mio caso, non è così. Cosa sto facendo di sbagliato qui?Problemi con l'algoritmo DCT e IDCT in 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; 
    } 
} 

E qui è la classe principale che va con esso:

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+"]"); 
      } 
     } 
    } 
} 

Ecco esempio di risultati:

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] 

Come indicato sopra, "Back to f" non mostra gli stessi valori contenuti in f inizialmente ...

+2

Qual è stato il caso di ingresso, qual è stato il risultato atteso, e ciò che il risultato effettivo? Hai provato a eseguire ciascuna routine su casi di input banali (ad es. [1 0; 0 0]) per scoprire quale era errata? –

+0

Che risultati ottieni quando dici di non ottenere di nuovo gli interi originali? Alcuni errori di arrotondamento in virgola mobile possono essere introdotti. – rsp

+0

DCT è in perdita. È necessario modificare il DCT (DCT senza perdita di dati) per ottenere operazioni senza perdita (reversibili). – osgx

risposta

8

Ho risolto questo problema, mi dispiace se la mia domanda non è chiara, ma lei E è quello che non era giusto: Il metodo IDCT doveva avere il coefficiente all'interno della i e j per i loop:

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; 
    } 

Questo funziona solo per un blocco 8x8 dei dati, altrimenti si dovrebbe cambiare questo:

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

in qualcosa di simile a questo:

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

Dove M e N sono i Dimensioni della tavola ...

Ecco i risultati con un blocco 2x2 di dati:

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]