简体   繁体   English

Java中二维矩阵的DCT和IDCT实现

[英]DCT and IDCT implementation in Java for 2-dimensional matrix

I already have an implementation for both the dct and idct, however they become very slow as the size of the matrix increases despite proper optimization. 我已经对dct和idct都有实现,但是尽管进行了适当的优化,但随着矩阵大小的增加,它们变得非常慢。 Does anyone know a faster implementation for both or any Java library that provides a faster implementation for a 2-dimensional case. 没有人知道两者的更快实现或任何为二维案例提供更快实现的Java库。 Thanks 谢谢

 public final double[][] initCoefficients(double[][] c) 
 {
    final int N = c.length;
    final double value = 1/Math.sqrt(2.0);

    for (int i=1; i<N; i++) 
    {
        for (int j=1; j<N; j++) 
        {
            c[i][j]=1;
        }
    }

    for (int i=0; i<N; i++) 
    {
        c[i][0] = value;
        c[0][i] = value;
    }
    c[0][0] = 0.5;
    return c;
}

/* Computes the discrete cosine transform
 */
public final double[][] forwardDCT(double[][] input) 
{
    final int N = input.length;
    final double mathPI = Math.PI;
    final int halfN = N/2;
    final double doubN = 2.0*N;

    double[][] c = new double[N][N];
    c = initCoefficients(c);

    double[][] output = new double[N][N];

    for (int u=0; u<N; u++) 
    {
        double temp_u = u*mathPI;
        for (int v=0; v<N; v++) 
        {
            double temp_v = v*mathPI;
            double sum = 0.0;
            for (int x=0; x<N; x++) 
            {
                int temp_x = 2*x+1;
                for (int y=0; y<N; y++) 
                {
                    sum += input[x][y] * Math.cos((temp_x/doubN)*temp_u) * Math.cos(((2*y+1)/doubN)*temp_v);
                }
            }
            sum *= c[u][v]/ halfN;
            output[u][v] = sum;
        }
    }
    return output;
}

/* 
 * Computes the inverse discrete cosine transform
 */
public final double[][] inverseDCT(double[][] input) 
{
    final int N = input.length;
    final double mathPI = Math.PI;
    final int halfN = N/2;
    final double doubN = 2.0*N;

    double[][] c = new double[N][N];
    c = initCoefficients(c);

    double[][] output = new double[N][N];


    for (int x=0; x<N; x++) 
    {
        int temp_x = 2*x+1;
        for (int y=0; y<N; y++) 
        {
            int temp_y = 2*y+1;
            double sum = 0.0;
            for (int u=0; u<N; u++) 
            {
                double temp_u = u*mathPI;
                for (int v=0; v<N; v++) 
                {
                    sum += c[u][v] * input[u][v] * Math.cos((temp_x/doubN)*temp_u) * Math.cos((temp_y/doubN)*v*mathPI);
                }
            }
            sum /= halfN;
            output[x][y] = sum;
        }
   }
   return output;
}

Right now it's an O(n 4 ) algorithm, four nested loops all doing n iterations. 现在,它是一个O(n 4 )算法,四个嵌套循环都进行n次迭代。 Separability gets that down to O(n 3 ) (or O(n 2 log n) if you're feeling brave enough to try the Fast Cosine Transform). 可分离性将其降低到O(n 3 )(如果您足够勇敢尝试快速余弦变换,则可降低到O(n 2 log n))。 It's actually even simpler than using the 2D formula, because all it is is this: 实际上,它甚至比使用2D公式还要简单,因为它就是这样:

  • run 1D DCT on all rows 在所有行上运行一维DCT
  • run 1D DCT on all columns (of the previous result) 对所有列(先前结果的一列)运行一维DCT

Or (optionally), to make both parts exactly the same: 或者(可选)使两个部分完全相同:

  • run 1D DCT on all rows, saving the results transposed 在所有行上运行1D DCT,保存结果转置
  • just do that again 再做一次

The transpose means the second time it's really doing columns, and in the two transposes undo each other. 转置意味着它第二次真正在做列,并且在两次转置中彼此撤消。

So, the cosines. 因此,余弦。 You note that 你注意到

precomputing the cosine seems difficult since am computing the cosine of the inner (loop) locals variables 因为要计算内部(循环)局部变量的余弦,所以预计算余弦似乎很困难

Those cosines are really just constants written down in formulaic form, that array depends only on n . 这些余弦实际上只是以公式形式写下来的常数,该数组仅取决于n For example, look at how FFmpeg does it in dctref.c 例如,在dctref.c中查看FFmpeg的工作方式

Do you have a max size for the DCT? DCT是否有最大尺寸? If working with integers is OK (and this is usually the case for image manipulation), you can find some fast implementations for size 4, 8, 16 and 32 there: https://github.com/flanglet/kanzi/tree/master/java/src/kanzi/transform 如果使用整数是可以的(通常是图像处理的情况),那么您可以在其中找到大小为4、8、16和32的一些快速实现: https : //github.com/flanglet/kanzi/tree/master / JAVA / SRC /坎兹/变换

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM