反向2D FFT以错误的顺序输出正确的值

时间:2015-06-02 20:33:48

标签: java algorithm image-processing fft

我的2D FFT算法正在输出正确的值,但它们的顺序错误。例如,输入:

1050.0  1147.0  1061.0  1143.0  
1046.0  1148.0  1118.0  1073.0  
1072.0  1111.0  1154.0  1101.0  
1078.0  1101.0  1106.0  1062.0  

采用FFT,然后反FFT得到:

1050.0  1143.0  1061.0  1147.0  
1078.0  1062.0  1106.0  1101.0  
1072.0  1101.0  1154.0  1111.0  
1046.0  1073.0  1118.0  1148.0  

你可以看到,如果你水平翻转最后3列,那么垂直最后3行,数据将是正确的。据我所知,对于所有输入大小都是如此,所以这是一个简单的(虽然是hacky)修复。然而,我担心修复的计算时间,因为我可能不得不在1024x1024或甚至2048x2048图像上执行此操作。

我相信我的1D FFT算法doFFT()是正确的,并且我得到了前向2D FFT的预期值。只是反向2D FFT导致了我的麻烦。

有人看到我的错误在哪里吗?

代码

private static double[] cose;
private static double[] sin;

public static void main(String[] args) {

    float[][] img = new float[][]{
        { 1050.0f, 1147.0f, 1061.0f, 1143.0f},
        { 1046.0f, 1148.0f, 1118.0f, 1073.0f},
        { 1072.0f, 1111.0f, 1154.0f, 1101.0f},
        { 1078.0f, 1101.0f, 1106.0f, 1062.0f}
    };

    int size = img.length;

    System.out.println("Image");
    for (int i = 0; i < size; i++)
    {
        for (int j = 0; j < size; j++)
        {
            System.out.print(img[i][j] + "\t");
        }
        System.out.println();
    }

    Complex[][] fft = fft2D(toComplex(img), false);

    Complex[][] inverse = fft2D(fft, true);

    System.out.println("\nInverse");
    for (int i = 0; i < size; i++)
    {
        for (int j = 0; j < size; j++)
        {
            System.out.print(inverse[i][j].getReal()  + "\t");
        }
        System.out.println();
    }

}

public static Complex[][] fft2D(Complex[][] pixels, boolean inverse){

    int size = pixels.length;
    computeCosSin(size);

    Complex[][] data = transpose(pixels.clone());

    Complex[] temp;

    // FFT of rows
    for (int i = 0; i < size; i++)
    {
        temp = doFFT(data[i], size);
        data[i] = temp;
    }

    // FFT of columns
    for (int i = 0; i < size; i++)
    {
        temp = new Complex[size];
        for (int j = 0; j < size; j++)
        {
            temp[j] = data[j][i];
        }
        Complex[] temp2 = doFFT(temp, size);
        for (int j = 0; j < size; j++)
        {
            data[j][i] = temp2[j];
        }
    }

    if (!inverse)
    {
        for (int i = 0; i < size; i++)
        {
            for (int j = 0; j < size; j++)
            {
                data[i][j] = data[i][j].divide(size*size);
            }
        }
    }
    return data;
}

public static Complex[] doFFT(Complex[] data, int size){

    Complex[] temp = new Complex[size];

    int j = 0;
    for (int i = 0; i < size; i++) {
        temp[i] = data[j];
        int k = size / 2;

        while ((j >= k) && (k > 0)) {
            j -= k;
            k /= 2;
        }
        j += k;
    }

    Complex n,m,h,f;
    for(int i=0; i<size;i+=4){
        n = temp[i].add(temp[i+1]);
        m = temp[i+2].add(temp[i+3]);
        h = temp[i].subtract(temp[i+1]);
        f = temp[i+2].subtract(temp[i+3]);
        Complex mult = h.add(f.multiply(Complex.I));
        Complex sub = h.subtract(f.multiply(Complex.I));

        temp[i] = n.add(m);
        temp[i+2] = n.subtract(m);
        temp[i+1] = sub;
        temp[i+3] = mult;
    }

    int u;
    for(int i=4; i< size;i<<=1){
        int v = size/(i <<1);

        for(int c=0; c< size;c +=i<<1){
            for(int x=0; x < i; x++){
                u = v*x;

                double calc = temp[i+c+x].getReal()*cose[u] - temp[i+c+x].getImaginary()*sin[u];
                double calc2 = temp[i+c+x].getReal()*sin[u] + temp[i+c+x].getImaginary()*cose[u];
                Complex fftArray = new Complex(calc,calc2);

                temp[(i+c+x)] =temp[(c+x)].subtract(fftArray);
                temp[(c+x)] = temp[(c+x)].add(fftArray);
            }
        }
    }

    return temp;
}

public static Complex[][] toComplex(float[][] arr)
{
    Complex[][] newArr = new Complex[arr.length][arr.length];
    for (int i = 0; i < arr.length; i++)
    {
        for (int j = 0; j < arr.length; j++)
        {
            newArr[i][j] = new Complex(arr[i][j], 0.0);
        }
    }
    return newArr;
}

public static Complex[][] transpose(Complex[][] array)
{
    for (int i = 0; i < array.length; i++)
    {
        for (int j = i+1; j < array[i].length; j++)
        {
            Complex temp = array[i][j];
            array[i][j] = array[j][i];
            array[j][i] = temp;

        }
    }
    return array;
}

public static void computeCosSin(int size){

    double num = (2.0*Math.PI)/size;
    double cos = Math.cos(num);
    double sine = Math.sin(num);

    cose = new double[size];
    sin = new double[size];

    cose[0] =1.0;

    for(int i=1; i<size;i++){
        cose[i] = cos*cose[i-1] + sine*sin[i-1];
        sin[i] = cos*sin[i-1] - sine*cose[i-1];
    }

}

}

1 个答案:

答案 0 :(得分:0)

这并不能解决根本问题,但它确实会改变我所获得的数据,因此它现在可以满足我的目的。我担心它在大型阵列上会非常慢。

该函数将行i与行N-i交换,然后将每列i与列N-i交换,0 <&lt;我&lt; N,(假设一个正方形,2输入数组的幂)

public Complex[][] inverseFix(Complex[][] array)
{
    int size = array.length;

    // Swap rows
    Complex[] temp;
    for (int i = 1; i < size/2; i++)
    {
        temp = array[i];
        array[i] = array[size-i];
        array[size-i] = temp;
    }

    // Swap columns
    Complex temp2;
    for (int i = 0; i < size; i++)
    {
        for (int j = 1; j < size/2; j++)
        {
            temp2 = array[i][j];
            array[i][j] = array[i][size-j];
            array[i][size-j] = temp2;
        }
    }
    return array;
}