Problems with DCT and IDCT algorithm in java
这里我的 DCT 算法类带有"applyDCT"和"applyIDCT"方法。从技术上讲,在对 0 到 255 之间的随机整数的 2x2 表进行正向 DCT(离散余弦变换)之后,然后立即对这些数字进行反向 DCT,我们应该回到我们最初拥有的原始整数。就我而言,情况并非如此。我在这里做错了什么?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | 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; } } |
这是与之配套的主要类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | 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+"]"); } } } } |
以下是结果示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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] |
如上所示,"回到f"并没有显示f最初包含的相同值...
我已经解决了这个问题,如果我的问题不清楚,我很抱歉,但这是不对的:IDCT 方法必须在 i 和 j for 循环中包含系数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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; } |
这仅适用于 8x8 数据块,否则您将不得不更改:
1 | (c[u]*c[v])/4.0) |
变成这样的:
1 |
其中 M 和 N 是表格的尺寸...
以下是 2x2 数据块的结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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] |