离散傅里叶的MFC算法详解(DFT,FFT,DCT)

来源:互联网 发布:淘宝网真皮手拿包 编辑:程序博客网 时间:2024/05/20 19:18
算法详解:离散时间傅里叶变换DFT 
转载源程序来自某书
---------------------
BOOL CDibImage::Fourier(LPSTR lpDIBBits, LONG lWidth, LONG lHeight)
{        
    unsigned char*    lpSrc;    // 指向源图像的指针
    double    dTemp;    
    LONG    i;                // 循环变量
    LONG    j;    
    LONG    w;                // 进行傅里叶变换的宽度(2的整数次方)
    LONG    h;                // 进行傅里叶变换的高度(2的整数次方)    
    int        wp;
    int        hp;       
    LONG    lLineBytes;        // 图像每行的字节数
    lLineBytes = WIDTHBYTES(lWidth * 8);    // 计算图像每行的字节数   
    // 赋初值
    w = 1;
    h = 1;
    wp = 0;
    hp = 0;
    
    // 计算能进行傅里叶变换的宽度和高度(2的整数次方)取整且是偶数。奇数另议。
    while(w * 2 <= lWidth)
    {
        w *= 2;
        wp++;//幂
    }    
    while(h * 2 <= lHeight)
    {
        h *= 2;
        hp++;//幂
    }   
    complex<double> *TD = new complex<double>[w * h];
    complex<double> *FD = new complex<double>[w * h];       
    for(i = 0; i < h; i++)            // 行
    {        
        for(j = 0; j < w; j++)        // 列
        {
            // 指向DIB第i行,第j个象素的指针
            lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i) + j;           
            // 给时域赋值
            TD[j + w * i] = complex<double>(*(lpSrc), 0);
        }
    }   
    for(i = 0; i < h; i++)
    {
        // 对y方向进行快速傅里叶变换
        FFT(&TD[w * i], &FD[w * i], wp);
    }   
    // 保存变换结果
    for(i = 0; i < h; i++)
    {
        for(j = 0; j < w; j++)
        {
            TD[i + h * j] = FD[j + w * i];//y变x,完成y方向一维运算,导入横方向做第二维运算。
        }
    }   
    for(i = 0; i < w; i++)
    {
        // 对x方向进行快速傅里叶变换
        FFT(&TD[i * h], &FD[i * h], hp);
    }       
    for(i = 0; i < h; i++)            // 行
    {        
        for(j = 0; j < w; j++)        // 列
        {
            // 计算频谱,求模
            dTemp = sqrt(FD[j * h + i].real() * FD[j * h + i].real() + FD[j * h + i].imag() * FD[j * h + i].imag()) / 100;
            if (dTemp > 255)
            {
                dTemp = 255;
            }           
            // 指向DIB第(i<h/2 ? i+h/2 : i-h/2)行,第(j<w/2 ? j+w/2 : j-w/2)个
            // 象素的指针,此处不直接取i和j,是为了将变换后的原点移到中心
            // lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight-1-i) + j;
            lpSrc = (unsigned char*)lpDIBBits + lLineBytes *
                (lHeight - 1 - (i<h/2 ? i+h/2 : i-h/2)) + (j<w/2 ? j+w/2 : j-w/2);//平移(h/2,w/2)
            // 更新源图像
            * (lpSrc) = (BYTE)(dTemp);
        }
    }   
    delete TD;
    delete FD;
    return TRUE;
}

算法详解:基2时间抽取FFT    
转载
这是我修改出来的第一个算法,花费了不少时间。主要是卡在c语言和变量传递上。
---------------------------------------------------------
VOID CDibImage::FFTTIME(complex<double> * TD, complex<double> * FD, int r)
{    
    LONG    count;                // 付立叶变换总点数    
    int        i,j,k;                // 循环变量
    int        N,p;                //N为当前每组点数
    double    w;                    // 弧度    
    complex<double> *W,*X1,*X2,*X,*z;
    
    count = 1 << r;                // 计算付立叶变换总点数,r为总幂
    
    // 分配运算所需存储器
    W  = new complex<double>[count/2];                    //count为接收点数(256,512等)
    X1 = new complex<double>[count];
    X2 = new complex<double>[count];
    
    // 计算加权系数(旋转因子W),w为弧度
    for(i = 0; i < count/2; i++)
    {
        w = -i * PI * 2 / count;
        W[i] = complex<double> (cos(w), sin(w));            //cos实部
    }   
    // 将时域点写入X1,X1为输入,X2为输出
//    memcpy(X1, TD, sizeof(complex<double>) * count);
    
// 重新排序,从最低位到最高位检查正序数的每一位i,然后把该位的值赋给倒序数的相应位
    //在倒序数中为第r-i-1位,r为序数的位数。二进制正序右边为低位
        for(j = 0; j < count; j++)
    {
        p = 0;
        for(i = 0; i < r; i++)    //二进制的i位,0...r-1
        {    
            if (j&(1<<i))         //j按位与位数,若非0则进入循环
            {   
                p+=1<<(r-i-1);    //如果正序数中位i的值为1,则倒序数中r-i-1的相应位置1。p+是累加其他所有位的1
            }
        }
           X1[j]=TD[p];        //对位       
    }
    // 快速付立叶变换(基2时间抽取),k对调r-k-1
    for(k =0 ; k < r; k++)                                  //k为当前幂,k=0为第1级
    {          
            N = 1 <<k+1;    //N为当前幂每组点数,频率抽取第一级最多,k=0,N=2^r,512-256-128....2
            for(i = 0; i < N / 2; i++)          //i为当前幂每组半点,所以后面两个半组一起算
            {
              for(j = 0; j < count/N; j++)//j为当前幂的组数,k=0时第1级有1组(j=0),k=1时第2级有2组
                {
                p = j * N;                    //p为当前幂组外间隔,即算到第j组时跨过的总点数
                X2[i + p] = X1[i + p] + X1[i + p + N / 2]* W[i * (1<<r-k-1)];  //每组上半,N/2为间组内隔,256-128....1                
                X2[i + p + N / 2] = X1[i + p] - X1[i + p + N / 2] * W[i * (1<<r-k-1)];//每组下半,[]内为W上标,为每组半点*组数
                }
            }       
        X  = X1;
        X1 = X2;
        X2 = X;
    }       
    for(j = 0; j < count; j++)
    {   
        FD[j]=X1[j];              //对位
    }   
    delete W;
    delete X1;
    delete X2;
}
0 0
原创粉丝点击