2010-11-21 4 views
5

Hier habe ich meine DCT-Algorithmus-Klasse mit "ApplyDCT" und "ApplyIDCT" -Methoden. Technisch gesehen, nachdem eine DCT (diskrete Kosinustransformation) auf einer 2x2-Tabelle von zufälligen ganzen Zahlen zwischen 0 und 255 durchgeführt wurde und dann sofort eine umgekehrte DCT für diese Zahlen durchgeführt wurde, sollten wir zu den ursprünglichen ganzen Zahlen zurückkehren, die wir an erster Stelle hatten. In meinem Fall ist das nicht so. Was mache ich hier falsch?Probleme mit DCT und IDCT-Algorithmus 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; 
    } 
} 

Und hier ist die Hauptklasse, die mit ihm geht:

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

Hier sind Beispiel der Ergebnisse:

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] 

Wie oben gezeigt, "Back to f" nicht zeigen die gleichen Werte in f enthalten anfänglich ...

+2

Was die Eingabe Fall war, was das erwartete Ergebnis war, und das, was das tatsächliche Ergebnis? Haben Sie versucht, jede Ihrer Routinen in trivialen Eingabefällen auszuführen (z. B. [1 0; 0 0]), um herauszufinden, welche falsch war? –

+0

Welche Ergebnisse erhalten Sie, wenn Sie sagen, dass Sie Ihre ursprünglichen Ganzzahlen nicht zurückbekommen? Einige Gleitkomma-Rundungsfehler können eingeführt werden. – rsp

+0

DCT selbst ist verlustreich. Sie benötigen eine modifizierte DCT (verlustfreie DCT), um einen verlustfreien (reversiblen) Betrieb zu erhalten. – osgx

Antwort

8

Ich habe dieses Problem gelöst, es tut mir leid, wenn meine Frage unklar war, aber sie e ist, was nicht richtig war: Die IDCT Methode die Koeffizienten in der i und j für Schleifen haben mußte:

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

Dies funktioniert nur für einen 8x8-Block von Daten oder sonst würden Sie dies ändern:

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

in etwa wie folgt:

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

Wo M und N die dimentions der Tabelle sind ...

Hier sind die Ergebnisse mit einem 2x2-Block von Daten:

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]