zoukankan      html  css  js  c++  java
  • 傅里叶变换

    对于傅里叶的各种推倒证明这里不提,本文着重‘看公式写代码’。
     
    一维离散福利叶变换的公式:
     
        
     
    反傅里叶:
        
        
     
     
     
    /*  
        函数:FFT2
        功能:(反)傅里叶变换 --- 基2
        参数:ptd -- in 空域
                  pfd -- out 频域
                  nlevel --- in 步数
                  sign --- 1 反傅里叶 -1 傅里叶
    */

    void FFT2(complex *pTd , complex * pFd , int nlevel,int sign) 
    {
        int nLength = pow(2.0,1.0*nlevel);
        complex * pw = (complex * )malloc(nLength * sizeof(complex));
        for (int i = 0 ; i <nLength ; ++i)
        {
            pw[i].real = 0.0 ;
            pw[i].image = 0.0;
        }
        double angle = 0.0;
        for (int i = 0 ; i < nLength ;++i)
        {
            for (int j = 0 ; j < nLength ; ++j)
            {
                angle = 2.0*CV_PI * i * j* sign / nLength ;
                pFd[i]+=(complex(cos(angle) , sin(angle)) *pTd[j]);
            }
        }

        if (sign == 1)
        {
            for (int i = 0 ; i < nLength ; ++i)
                pFd[i]/=nLength;    
        }
        free(pw);
    }
     
     
     
    上述算法(DFT)的复杂度为 N * N (N个点每个点的变换都有N点参与运算),而基2快速傅里叶变换(FFT)则降低了复杂度达到 N * log
     
    (N)/log(2)(N个点每个点的变换有log(N)/log(2)个点参与运算),主要是利用傅里叶公式的周期性 对称性减少了重复计算,具体推导参考
     
    相关书籍,网上大多有对FFT的推导或者直接给出代码,本文主要对代码解释。
     
     
     
    1.位变换
     
    从上图1看出 x0(000) -- 变换后为x0(000) x1(001)---x4(100) x2(010)---x2(010)等等
     
    位变换的意思是 比如 1100 变换后为 0011 ,通俗的理解就是 1100 从左往右开始对应1的位置 ,变换成 从右往左为对应位置为1(0011)
     
    2.蝶形运算
     
    如何来的:
    别别看上面的推导了,晕忽忽的~~ ,总之就是各种对称性 周期性以后成了最后的样子
     
    如果以F1(K),F2(K)为最终运算的话那就错了,对应公式中来看F1(K),F2(K)的计算还是要有其他点做贡献的,所以要对F1(K),F2(K)再分解一
     
    一直到不能分解为止,图1是 N=8的分解情况及对应关系。
     
    这里提出三个辅助名词 :级数level 跨度间隔B 加权系数P
     
    图1:
     
    总数为8  level = log(8)/log(2) = 3
     
    B=1,2,4 每一级增加一倍
     
    P=0 , 0 2 , 0 1 2 3  每一级增加一倍
     
    图2:
     
    总数为16  level = log(16)/log(2) = 4
     
    B=1,2,4,8 每一级增加一倍
     
    P=0 , 0 4 , 0  2 4,6, 0 1 2 3 4 5 6 7  每一级增加一倍
     
    依次类推....................好吧从这里找规律,下面代码就是这么来的。
     
    void FFT(complex *pTd , complex * pFd , int nlevel,int sign) 
    {
        //nLength = 2 ^nlevel

        int nLength = pow(2.0,1.0*nlevel);

        //求W = e ^(-j*2*PI/nlength) = cos(-2*PI/nlength) + j*sin(-2*PI/nlength)
        complex *pw = (complex *)malloc(nLength *sizeof(complex)/2);
        double angle = 0.0;
        for (int i = 0 ; i <nLength/2 ;++i)
        {
            angle =CV_PI *sign *2.0 * i /nLength ;
            pw[i] = complex(cos(angle),sin(angle));
        }

        //位变换
        int p = 0 ;
        for (int i = 0 ; i <nLength ;++i)
        {
            p = 0 ;
            for (int j = 0 ; j <nlevel ; ++j)
            {
                if (i & (1<< j) )
                    p+=1<<(nlevel - j -1);
            }
            pFd[p] = pTd[i];
        }

        //蝶形算法
        int B=0; //跨度间隔
        int weight = 0 ; //加权系数
        complex *x1 = (complex *)malloc(nLength * sizeof(complex));
        for (int i = 0 ; i <nlevel ; ++i)
        {
            B = 1<<i; //跨度间隔 1 ,2 ,4 ,8 ..............
            for (int j =0 ; j <B; ++j)
            {
                weight = (1<<(nlevel - i -1)) * j;
                for (int k = j ; k <nLength ; k+=(1<<(i+1)))
                {
                    x1[k] = pFd[k] + pFd[k+B] * pw[weight];
                    x1[k+B] = pFd[k] - pFd[k+B]*pw[weight];
                }
            }
            memcpy(pFd,x1,nLength * sizeof(complex));
        }

        if (sign == 1)
        {
            for (int i = 0 ; i < nLength ; ++i)
                pFd[i]/=nLength;    
        }
        free(pw);
        free(x1);
    }





    作者: 小马_xiao

    出处:http://www.cnblogs.com/xiaomaLV2/>

    关于作者:专注halcon\opencv\机器视觉

    本文版权归作者,未经作者同意必须保留此段声明,且在文章页面明显位置给出 原文链接

  • 相关阅读:
    撕衣服的简易实现
    简易的画画板的实现
    图片简易处理
    在内存中创建原图的副本
    缩放图片并加载到内存中
    加载大图片的OOM异常
    计算机表示图形的形式
    虚拟短信
    ContentProvider 共享数据
    内容观察者
  • 原文地址:https://www.cnblogs.com/xiaomaLV2/p/2579532.html
Copyright © 2011-2022 走看看