使用OpenCV作为数据源,使用CUFFT实现实到复FFT

使用OpenCV作为数据源,使用CUFFT实现实到复FFT,opencv,cuda,fft,Opencv,Cuda,Fft,我在尝试使用cuFFT对浮点数组执行二维变换时遇到了一个问题。我看了一下文档,但有些信息相互矛盾/不清楚;所以我有几个问题: 我的数据是480行,有640列(例如float data[480][640]但在单个维度中,所以float data[480*640]) 如果我们说我的输入维度(真实数据)是N1=480和N2=640。尺寸(经过实到复变换后)是否为N1=480、N2=321 我可以cudaMemcpy将数据直接放入相同大小的cufftReal数组中吗?或者它必须是一个cufftCompl

我在尝试使用cuFFT对浮点数组执行二维变换时遇到了一个问题。我看了一下文档,但有些信息相互矛盾/不清楚;所以我有几个问题:

我的数据是
480
行,有
640
列(例如
float data[480][640]
但在单个维度中,所以
float data[480*640]

  • 如果我们说我的输入维度(真实数据)是
    N1=480
    N2=640
    。尺寸(经过实到复变换后)是否为N1=480、N2=321

  • 我可以
    cudaMemcpy
    将数据直接放入相同大小的
    cufftReal
    数组中吗?或者它必须是一个
    cufftComplex
    数组

    如果它必须是一个
    cufftComplex
    数组,我假设元素需要位于真实组件的位置

  • 给定上述值,调用
    cufftPlan2d
    cufftExecR2C
    cufftC2R
    的正确结构是什么

  • 我想现在就这些了

    非常感谢

    编辑:因此,我已经按照JackOLantern的建议实现了正向和反向变换。然而,我的结果并不是我所期望的(FFT后的结果与FFT前的结果相同)。我有一个演示两组示例的示例。第一个来自我的房间,第二个来自我的大学项目

    在cuFFT文档中,
    cufftPlan2d
    的使用存在歧义(因此我提出了问题)。在文档中,对于二维数组,数据应如上所述输入(
    float data[480][640]==float data[NY][NX]
    ),因此
    NY
    表示行。但是,在
    cufftPlan2d
    的函数列表中,它指出
    nx
    (参数)用于行

    在函数调用中交换
    NX
    NY
    的值会得到与项目图像相同的结果(方向正确,但以正常大小的1/4分割为三个部分重叠的图像),但是,使用JackOLantern在其答案中陈述的参数会得到倾斜/扭曲的结果

    我做错什么了吗?还是说cuFFT库在这方面有问题

    另外:我已经撤销了JackOLantern对这个问题的一些编辑,因为我的问题可能源于我的数据来自OpenCV

    1) 如果我们说我的输入维度(真实数据)是N1=480和N2=640。尺寸(从实到复变换后)N1=480,N2=321

    cufftExecR2C的输出是一个
    NX*(NY/2+1)
    cufftComplex
    矩阵。因此,在您的例子中,您将有一个
    480x321
    float2
    矩阵作为输出

    2) 我可以将数据直接压缩到相同大小的
    cufftReal
    数组中吗?或者它必须是一个
    cufftComplex
    数组

    如果它必须是一个
    cufftComplex
    数组,我假设元素需要位于真实组件的位置

    可以,您可以将数据复制到
    cufftReal
    数组和
    N1xN2
    数据

    3) 给定上述值,调用
    cufftPlan2d
    cufftExecR2C
    cufftC2R
    的正确结构是什么


    编辑:我最近发现是我在使用函数的方式上犯了错误

    最初我认为函数定义指的是传递给它的数据的大小

    然而,看起来这些参数实际上直接指的是真实零件的尺寸

    这意味着参数指的是:

    • 使用R2C时输入数据的大小(从实到复)
    • 使用C2R时输出数据的大小(从复数到实数)

    因此,cuFFT文档和库本身似乎不一致

    当执行R2C后接C2R(分别为实数到复数、复数到实数)时,文件规定,对于NX NY维度的实数输入,复数输出为NX(地板(NY/2)+1);反之亦然

    但是实际输出的尺寸为NX NY,实际输入的尺寸为NX NY。这个在第一页提到(一半),作为

    C2R-对称复数输入到实输出

    这意味着复杂数据必须是对称的,即除了非冗余数据外,还必须具有冗余数据

    文档中还有许多其他矛盾之处,我将不详细介绍

    不用说,问题已经解决了


    我在下面附上了一个MWE。顶部附近有几行带有
    #define NUM_C2
    和适当注释。更改此项将更改是遵循文档格式还是我的“修复”

    输出是

  • 输入真实数据
  • 中间复杂数据
  • 输出真实数据
  • 输出数据与输入数据的比率(FFT误差较小,~1表示正确)
  • 请随意更改参数(NUM_R和NUM_C),如果您认为我在某个地方犯了错误,请随意评论

    #include <iostream>
    #include <math.h>
    #include <cufft.h>
    
    // e.g. float data[NUM_R][NUM_C]
    #define NUM_R 12
    #define NUM_C 16
    
    // Documentation Version
    //#define NUM_C2 (1+NUM_C/2)
    // "Correct" Version
    #define NUM_C2 NUM_C
    
    using namespace std;
    
    int main(int argc, char** argv)
    {
        cufftReal *in_h, *out_h, *in_d, *out_d;
        cufftComplex *mid_d, *mid_h;
        cufftHandle pF, pI;
        int r, c;
    
        in_h = (cufftReal*) malloc(NUM_R * NUM_C * sizeof(cufftReal));
        out_h= (cufftReal*) malloc(NUM_R * NUM_C * sizeof(cufftReal));
        mid_h= (cufftComplex*)malloc(NUM_C2*NUM_R*sizeof(cufftComplex));
    
        cudaMalloc((void**) &in_d, NUM_R * NUM_C * sizeof(cufftReal));
        cudaMalloc((void**)&out_d, NUM_R * NUM_C * sizeof(cufftReal));
        cudaMalloc((void**)&mid_d, NUM_C2 * NUM_R * sizeof(cufftComplex));
    
        cufftPlan2d(&pF, NUM_R, NUM_C, CUFFT_R2C);
        cufftPlan2d(&pI, NUM_R,NUM_C2, CUFFT_C2R);
    
        cout<<endl<<"------"<<endl;    
        for(r=0; r<NUM_R; r++) 
        {
            for(c=0; c<NUM_C; c++)
            {
                in_h[c + NUM_C * r] = cos(2.0*M_PI*(c*7.0/NUM_C+r*3.0/NUM_R));  
                out_h[c+ NUM_C * r] = 0.f;
                cout<<in_h[c+NUM_C*r];
                if(c<(NUM_C-1)) cout<<", ";
                else cout<<endl;
            }
        }
    
        cudaMemcpy((cufftReal*)in_d, (cufftReal*)in_h, NUM_R * NUM_C * sizeof(cufftReal),cudaMemcpyHostToDevice);
    
        cufftExecR2C(pF, (cufftReal*)in_d, (cufftComplex*)mid_d);
    
        cudaMemcpy((cufftComplex*)mid_h, (cufftComplex*)mid_d, NUM_C2*NUM_R*sizeof(cufftComplex), cudaMemcpyDeviceToHost);
    
        cout<<endl<<"------"<<endl;    
        for(r=0; r<NUM_R; r++) 
        {
            for(c=0; c<NUM_C2; c++)
            {
                cout<<mid_h[c+(NUM_C2)*r].x<<"|"<<mid_h[c+(NUM_C2)*r].y;
                if(c<(NUM_C2-1)) cout<<", ";
                else cout<<endl;
            }
        }
    
    
        cufftExecC2R(pI, (cufftComplex*)mid_d, (cufftReal*)out_d);
    
        cudaMemcpy((cufftReal*)out_h, (cufftReal*)out_d, NUM_R*NUM_C*sizeof(cufftReal), cudaMemcpyDeviceToHost);
    
        cout<<endl<<"------"<<endl;    
    
        for(r=0; r<NUM_R; r++) 
        {
            for(c=0; c<NUM_C; c++)
            {
                cout<<out_h[c+NUM_C*r]/(NUM_R*NUM_C);
                if(c<(NUM_C-1)) cout<<", ";
                else cout<<endl;
            }
        }
    
        cout<<endl<<"------"<<endl;    
    
        for(r=0; r<NUM_R; r++) 
        {
            for(c=0; c<NUM_C; c++)
            {
                cout<<(out_h[c+NUM_C*r]/(NUM_R*NUM_C))/in_h[c+NUM_C*r];
                if(c<(NUM_C-1)) cout<<", ";
                else cout<<endl;
            }
        }
        free(in_h);
        free(out_h);
        free(mid_h);
        cudaFree(in_d);
        cudaFree(out_h);
        cudaFree(mid_d);
    
        return 0;
    }
    
    #包括
    #包括
    #包括
    //例如,浮点数据[NUM_R][NUM_C]
    #定义NUM_R 12
    #定义NUM_C 16
    //文件版本
    //#定义数量C2(1+数量C/2)
    //“正确”版本
    #定义NUM_C2 NUM_C
    使用名称空间std;
    int main(int argc,字符**argv)
    {
    卡夫特雷尔*进,出,进,出;
    袖口复合体*mid_d,*mid_h;
    f,pI;
    int r,c;
    in_h=(cufftReal*)malloc(NUM_R*NUM_C*sizeof(cufftReal));
    out_h=(cufftReal*)malloc(NUM_R*NUM_C*sizeof(cufftReal));
    mid_h=(袖套复合体*)malloc(NUM_C2*NUM_R*sizeof(袖套复合体));
    cudamaloc((void**)和in_d,NUM_R*NUM_C*sizeof(cufftReal));
    
    #include <iostream>
    #include <math.h>
    #include <cufft.h>
    
    // e.g. float data[NUM_R][NUM_C]
    #define NUM_R 12
    #define NUM_C 16
    
    // Documentation Version
    //#define NUM_C2 (1+NUM_C/2)
    // "Correct" Version
    #define NUM_C2 NUM_C
    
    using namespace std;
    
    int main(int argc, char** argv)
    {
        cufftReal *in_h, *out_h, *in_d, *out_d;
        cufftComplex *mid_d, *mid_h;
        cufftHandle pF, pI;
        int r, c;
    
        in_h = (cufftReal*) malloc(NUM_R * NUM_C * sizeof(cufftReal));
        out_h= (cufftReal*) malloc(NUM_R * NUM_C * sizeof(cufftReal));
        mid_h= (cufftComplex*)malloc(NUM_C2*NUM_R*sizeof(cufftComplex));
    
        cudaMalloc((void**) &in_d, NUM_R * NUM_C * sizeof(cufftReal));
        cudaMalloc((void**)&out_d, NUM_R * NUM_C * sizeof(cufftReal));
        cudaMalloc((void**)&mid_d, NUM_C2 * NUM_R * sizeof(cufftComplex));
    
        cufftPlan2d(&pF, NUM_R, NUM_C, CUFFT_R2C);
        cufftPlan2d(&pI, NUM_R,NUM_C2, CUFFT_C2R);
    
        cout<<endl<<"------"<<endl;    
        for(r=0; r<NUM_R; r++) 
        {
            for(c=0; c<NUM_C; c++)
            {
                in_h[c + NUM_C * r] = cos(2.0*M_PI*(c*7.0/NUM_C+r*3.0/NUM_R));  
                out_h[c+ NUM_C * r] = 0.f;
                cout<<in_h[c+NUM_C*r];
                if(c<(NUM_C-1)) cout<<", ";
                else cout<<endl;
            }
        }
    
        cudaMemcpy((cufftReal*)in_d, (cufftReal*)in_h, NUM_R * NUM_C * sizeof(cufftReal),cudaMemcpyHostToDevice);
    
        cufftExecR2C(pF, (cufftReal*)in_d, (cufftComplex*)mid_d);
    
        cudaMemcpy((cufftComplex*)mid_h, (cufftComplex*)mid_d, NUM_C2*NUM_R*sizeof(cufftComplex), cudaMemcpyDeviceToHost);
    
        cout<<endl<<"------"<<endl;    
        for(r=0; r<NUM_R; r++) 
        {
            for(c=0; c<NUM_C2; c++)
            {
                cout<<mid_h[c+(NUM_C2)*r].x<<"|"<<mid_h[c+(NUM_C2)*r].y;
                if(c<(NUM_C2-1)) cout<<", ";
                else cout<<endl;
            }
        }
    
    
        cufftExecC2R(pI, (cufftComplex*)mid_d, (cufftReal*)out_d);
    
        cudaMemcpy((cufftReal*)out_h, (cufftReal*)out_d, NUM_R*NUM_C*sizeof(cufftReal), cudaMemcpyDeviceToHost);
    
        cout<<endl<<"------"<<endl;    
    
        for(r=0; r<NUM_R; r++) 
        {
            for(c=0; c<NUM_C; c++)
            {
                cout<<out_h[c+NUM_C*r]/(NUM_R*NUM_C);
                if(c<(NUM_C-1)) cout<<", ";
                else cout<<endl;
            }
        }
    
        cout<<endl<<"------"<<endl;    
    
        for(r=0; r<NUM_R; r++) 
        {
            for(c=0; c<NUM_C; c++)
            {
                cout<<(out_h[c+NUM_C*r]/(NUM_R*NUM_C))/in_h[c+NUM_C*r];
                if(c<(NUM_C-1)) cout<<", ";
                else cout<<endl;
            }
        }
        free(in_h);
        free(out_h);
        free(mid_h);
        cudaFree(in_d);
        cudaFree(out_h);
        cudaFree(mid_d);
    
        return 0;
    }