zoukankan      html  css  js  c++  java
  • 离散傅里叶变换的实现与在图像中的应用

    c++实现二维离散傅里叶变换:

    基于快速傅里叶蝶形算法

      1 #include <stdio.h>
      2 #include <iostream>
      3 #include <complex>
      4 #include <bitset>
      5 #include <fstream>
      6 #include <algorithm>
      7 #include <iterator>
      8 #include <math.h>
      9 #include "cv.h"
     10 #include "highgui.h"
     11 #include "CImg.h"
     12 #define pi 3.1415926535
     13 using std::iostream;
     14 using std::bitset;
     15 using std::complex;
     16 using namespace std;
     17 using namespace cimg_library;
     18 
     19 int rev(int k,int n)
     20 {
     21      bitset<32> tmp(k);
     22      bitset<32> dist;
     23      for(int m = 0;m<n;m++)
     24      {
     25         if(tmp.test(m))
     26         {
     27             dist.set(n-1-m);
     28         }
     29      }
     30      int revk = (int)dist.to_ulong();
     31      return revk;
     32 }
     33 //重载形式
     34 complex<double>* FFT(const complex<double> *srcimg,int n)
     35 {
     36     double flag = log10((double)n)/log10(2.0);
     37     int N = n;
     38     if(flag - (int)flag != 0){   //判断是否为2的指数次
     39         cout <<"the length of srcimg is wrong"<< endl;
     40         /*填充成2的指数项*/
     41         cout <<"need padding"<<endl;
     42         N = pow(2,(double)((int)flag+1));
     43         flag = log10((double)N)/log10(2.0);
     44     }
     45     /*改变成奇偶顺序*/
     46     complex<double> *arr= new complex<double>[N];
     47     int sub;
     48     for(int k =0;k<N;k++)
     49     {
     50         sub =rev(k,(int)flag); 
     51         if(sub <= n-1){
     52             arr[k] = *(srcimg + sub);
     53         }else{
     54             complex<double> t = complex<double>(0,0);
     55             arr[k] = t;
     56         }
     57     }
     58 //    cout<<"------------after padding and retrival-----------------"<<endl;
     59 //    for(size_t y=0;y<N;y++)
     60 //    {
     61 //        cout << arr[y].real()<<"  "<<arr[y].imag()<<endl;
     62 //    }
     63 
     64     /*基于迭代的蝶形快速傅立叶变换,自底向上*/
     65      for(int s =1;s <= flag;s++)
     66     {
     67         int m = pow(2,(double)s);
     68         complex<double> wm = complex<double>(cos(2*pi/m),sin(2*pi/m));//wm1:从W21开始,周期变换
     69         for(int p = 0;p<N;p+=m)
     70         {
     71             complex<double> w(1,0);
     72             for(int j = 0;j<=m/2-1;j++)
     73             {
     74                 complex<double> t = w * arr[p+j+m/2];
     75                 complex<double> u = arr[p+j];
     76                 arr[p+j] = u+t;
     77                 arr[p+j+m/2] = u-t;
     78                 w = w*wm;
     79             }
     80         }
     81     }
     82     return arr;
     83 }
     84 /***********一维快速傅立叶变换********************
     85 *srcimg : 原始一维序列                          *
     86 *n     :一维序列的长度
     87 *************************************************/
     88 complex<double>* FFT(const double *srcimg,int n)
     89 {
     90     double flag = log10((double)n)/log10(2.0);
     91     int N = n;
     92     if(flag - (int)flag != 0){   //判断是否为2的指数次
     93 //        cout <<"the length of srcimg is wrong"<< endl;
     94         /*填充成2的指数项*/
     95 //        cout <<"need padding"<<endl;
     96         N = pow(2,(double)((int)flag+1));
     97         flag = log10((double)N)/log10(2.0);
     98     }
     99     /*改变成奇偶顺序*/
    100     complex<double> *arr= new complex<double>[N];
    101     int sub;
    102     for(int k =0;k<N;k++)
    103     {
    104         sub =rev(k,(int)flag); 
    105         if(sub <= n-1){
    106             arr[k] = complex<double>(*(srcimg + sub),0);
    107         }else{
    108             complex<double> t = complex<double>(0,0);
    109             arr[k] = t;
    110         }
    111     }
    112 //    cout<<"------------after padding and retrival-----------------"<<endl;
    113 //    for(size_t y=0;y<N;y++)
    114 //    {
    115 //        cout << arr[y].real()<<"  "<<arr[y].imag()<<endl;
    116 //    }
    117 
    118     /*基于迭代的蝶形快速傅立叶变换,自底向上*/
    119      for(int s =1;s <= flag;s++)
    120     {
    121         int m = pow(2,(double)s);
    122         complex<double> wm = complex<double>(cos(2*pi/m),sin(2*pi/m));//wm1:从W21开始,周期变换
    123         for(int p = 0;p<N;p+=m)
    124         {
    125             complex<double> w(1,0);
    126             for(int j = 0;j<=m/2-1;j++)
    127             {
    128                 complex<double> t = w * arr[p+j+m/2];
    129                 complex<double> u = arr[p+j];
    130                 arr[p+j] = u+t;
    131                 arr[p+j+m/2] = u-t;
    132                 w = w*wm;
    133             }
    134         }
    135     }
    136     return arr;
    137 }
    138 int countPadding(int n);
    139 /*****************一维快速傅立叶逆变换********************/
    140 /*fftimg:原始一维傅立叶序列
    141   n     : 序列长度
    142 *******************************************************/
    143 complex<double>* IFFT(const complex<double> *fftimg,int n)
    144 {
    145     n = countPadding(n);
    146     double flag = log10((double)n)/log10(2.0);
    147     int N = n;
    148     if(flag - (int)flag != 0){   //判断是否为2的指数次
    149         cout <<"the length of srcimg is wrong"<< endl;
    150         /*填充成2的指数项*/
    151         cout <<"need padding"<<endl;
    152         N = pow(2,(double)((int)flag+1));
    153         flag = log10((double)N)/log10(2.0);
    154     }
    155     /*改变成奇偶顺序*/
    156     complex<double> * spit = new complex<double>[N];
    157     int sub=0;
    158     for(int k =0;k<N;k++)
    159     {
    160         sub =rev(k,(int)flag); 
    161         if(sub < n){
    162             spit[k] = complex<double>(*(fftimg + sub));
    163         }else{
    164             spit[k] = complex<double>(0,0);
    165         }
    166     }
    167 
    168     for(int s =1;s <= flag;s++)
    169     {
    170         int m = pow(2,(double)s);
    171         complex<double> wm = complex<double>(cos(-2*pi/m),sin(-2*pi/m));//wm1:从W2(-1)开始
    172         for(int p = 0;p<N;p+=m)
    173         {
    174             complex<double> w(1,0);
    175             for(int j = 0;j<=m/2-1;j++)
    176             {
    177                 complex<double> t = w * spit[p+j+m/2];
    178                 complex<double> u = spit[p+j];
    179                 spit[p+j] = u+t;
    180                 spit[p+j+m/2] = u-t;
    181                 w = w*wm;
    182             }
    183         }
    184     }
    185 
    186     for(size_t p =0;p<n;p++)
    187     {
    188         spit[p] = spit[p]/complex<double>(N,0);
    189     }
    190     return spit;
    191 }
    192 /*******使用共轭的快速傅立叶逆变换**************/
    193 complex<double>* IFFT2(const complex<double> *fftimg,int n)
    194 {
    195     n = countPadding(n);
    196     complex<double> *gfftimg = new complex<double>[n];
    197     for(size_t i = 0;i<n;i++){
    198         gfftimg[i] = complex<double>(fftimg[i].real(),-fftimg[i].imag());
    199     }
    200     complex<double> *ifft = FFT(gfftimg,n); 
    201     for(size_t j = 0;j<n;j++)
    202     {
    203         ifft[j] = ifft[j]/complex<double>(n,0);
    204     }
    205     delete gfftimg;
    206     return ifft;
    207 }
    208 
    209 /*************二维快速傅立叶变换**************************
    210 *srcimg:用一维表示的二维原始序列
    211 *width :宽度
    212 height:高度
    213 ********************************************************/
    214 complex<double>* twoDFFT(const double *srcimg,int width,int height)
    215 {
    216     int w = countPadding(width);
    217     int h = countPadding(height);
    218     int pixes = w * h;
    219     complex<double> *hdirection = new complex<double>[w];
    220     complex<double> *vdirection = new complex<double>[h];
    221     complex<double> *fourier = new complex<double>[pixes];
    222     /********移位居中************/
    223     /*二维水平方向*/
    224     for(size_t i = 0;i<h;i++){
    225         for(size_t j = 0;j<w;j++){
    226             if(i>=height || j >=width){
    227                 hdirection[j] = complex<double>(0,0);
    228             }else{
    229                 hdirection[j] = complex<double>(srcimg[i*width + j],0);
    230             }
    231     //        cout << hdirection[j] << " ";
    232         }
    233     //    cout <<""<<endl;
    234         complex<double> *hfourier = FFT(hdirection,w);
    235         for(size_t m = 0;m<w;m++){
    236             fourier[i*w+m] = hfourier[m];
    237         }
    238         delete hfourier;
    239     }
    240     /*二维垂直方向*/
    241     for(size_t ii = 0;ii<w;ii++){
    242         for(size_t jj = 0;jj<h;jj++){
    243             vdirection[jj] = fourier[jj*w + ii];
    244         }
    245         complex<double> *vfourier = FFT(vdirection,h);
    246         for(size_t mm = 0;mm < h;mm++){
    247             fourier[mm*w +ii] = vfourier[mm];
    248         }
    249         delete vfourier;
    250     }
    251     delete hdirection;
    252     delete vdirection;
    253     return fourier;
    254 
    255 }
    256 /**************二维快速傅立叶逆变换*************************
    257 *fourier : 一维表示的二维傅立叶变换序列
    258 *宽
    259 *height:高
    260 ********************************************/
    261 
    262 complex<double>* twoDIFFT(const complex<double> *fourier,int width,int height)
    263 {
    264     width = countPadding(width);
    265     height = countPadding(height);
    266     int fpoints = width * height;
    267     complex<double> *hdirection = new complex<double>[width];
    268     complex<double> *vdirection = new complex<double>[height];
    269     complex<double> *ifourier = new complex<double>[fpoints];
    270 
    271     for(size_t ii = 0;ii<height;ii++)
    272     {
    273         for(size_t jj = 0;jj<width;jj++){
    274             hdirection[jj] = fourier[ii*width+jj];
    275         }
    276         complex<double> *hifour = IFFT(hdirection,width);//临时变量
    277         for(size_t mm = 0;mm<width;mm++){
    278             ifourier[ii*width+mm] = hifour[mm];
    279         }
    280         delete hifour;
    281     }
    282     for(size_t i = 0;i<width;i++){
    283         for(size_t j = 0;j<height;j++){
    284             vdirection[j] = ifourier[j*width+i];
    285         }
    286         complex<double> *vifour = IFFT(vdirection,height);
    287         for(size_t m = 0;m<height;m++){
    288             ifourier[m*width+i] = vifour[m];
    289         }
    290         delete vifour;
    291     }    
    292     delete hdirection;
    293     delete vdirection;
    294     return ifourier;
    295 }
    296 /******计算填充数*********************/
    297 int countPadding(int n)
    298 {
    299     double lg = log10((double)n)/log10(2.0);
    300     if((lg - (int)lg) == 0){
    301         return n;
    302     }
    303     int N = pow(2.0,((int)lg+1));
    304     return N;
    305 }
    306 /*测试一维填充形式傅立叶变换*/
    307 /*
    308 int main()
    309 {
    310     ifstream infile("D:\ftest.txt");
    311     if(!infile.is_open())
    312     {
    313         cout<<"file read error"<<endl;
    314         return -1;
    315     }
    316     istream_iterator<double> df(infile);
    317     istream_iterator<double> eof;
    318     int N = *df++;
    319     double *src = new double[N];
    320     size_t i = 0;
    321     while(df != eof)
    322     {
    323         src[i] = *df++;
    324         i++;
    325     }
    326 /*    for(size_t a = 0;a < N;a++)
    327     {
    328         cout << src[a]<<endl;
    329     }
    330 */    
    331 //    complex<double> *fourier = new complex<double>[N];
    332 //    complex<double> *spit = new complex<double>[N];
    333 /*    complex<double> *fourier = FFT(src,N);
    334     cout <<"--------fourier sieres----------"<<endl;
    335     for(size_t x = 0;x <16;x++)
    336     {
    337         cout << (*(fourier +x)).real()<<"  "<<(*(fourier+x)).imag() << endl;
    338     }
    339     cout <<"----------------inverse fourier -----------------------"<<endl;
    340     complex<double> *spit = IFFT(fourier,N);
    341     for(size_t y = 0;y <16;y++)
    342     {
    343         cout << spit[y].real()<<"  "<<spit[y].imag() << endl;
    344     }
    345     delete src;
    346 //    delete fourier;
    347 //    delete spit;
    348     return 1;
    349 }*/
    350 /*测试二维零填充傅立叶正负变换*/
    351 
    352 /*
    353 int main()
    354 {
    355     ifstream infile("D:\ftest2.txt");
    356     if(!infile.is_open())
    357     {
    358         cout<<"file read error"<<endl;
    359         return -1;
    360     }
    361     istream_iterator<double> df(infile);
    362     istream_iterator<double> eof;
    363     int N = *df++;
    364     double *src = new double[N];
    365     size_t i = 0;
    366     while(df != eof)
    367     {
    368         src[i] = *df++;
    369         i++;
    370     }
    371     complex<double> *fourier = twoDFFT(src,3,6);
    372     cout <<"--------fourier sieres----------"<<endl;
    373     for(size_t x = 0;x <32;x++)
    374     {
    375         cout << (*(fourier +x)).real()<<"  "<<(*(fourier+x)).imag() << endl;
    376     }
    377     cout <<"----------------inverse fourier -----------------------"<<endl;
    378     complex<double> *spit = twoDIFFT(fourier,3,6);
    379     for(size_t y = 0;y <32;y++)
    380     {
    381         cout << spit[y].real()<<"  "<<spit[y].imag() << endl;
    382     }
    383     delete src;
    384 //    delete fourier;
    385 //    delete spit;
    386     return 1;
    387 }*/
    388 
    389 /*测试一维傅里叶图像变换*//*
    390 int main(int argc,char ** argv)
    391 {
    392     IplImage *img;
    393     img = cvLoadImage("F:\Fig0222(a)(face).tif",0);
    394     int dim = img->imageSize;
    395     //从图像矩阵复制出单维数组;
    396     double * src = new double[dim];
    397     size_t j =0;
    398     for(int y =0;y<img->height;y++)
    399     {
    400         uchar * ptr = (uchar*)(img->imageData + y * img->widthStep);
    401         for(int x =0;x<img->width;x++){
    402             src[j] = (double)ptr[x]/256;
    403             j++;
    404         }
    405     }
    406     //一维数组做傅立叶变换
    407     complex<double>* fourier = FFT(src,dim);
    408     //计算填充后傅氏数组大小
    409     double lg = log10((double)dim)/log10(2.0);
    410     int n = pow(2,(double)((int)lg+1));
    411     //傅立叶逆变换
    412     complex<double> *ifourier = IFFT(fourier,n);
    413     double ipix = 0;
    414     size_t po = 0;
    415     //重填充图像
    416     for(int y =0;y<img->height;y++)
    417     {
    418         uchar * ptr = (uchar*)(img->imageData + y * img->widthStep);
    419         for(int x =0;x<img->width;x++){
    420             ipix = ifourier[po].real();
    421             ptr[x] = (uchar)(ipix * 256);
    422             po++;
    423         }
    424     }
    425     cvNamedWindow("fourier_t",CV_WINDOW_AUTOSIZE);
    426     cvShowImage("fourier_t",img);
    427     cvWaitKey(0);
    428     cvReleaseImage(&img);
    429     cvDestroyWindow("fourier_t");
    430 
    431     return 1;
    432 /*    ifstream infile("F:\Fig0222(a)(face).tif",ios::binary);
    433     vector<double> collection;
    434     istream_iterator<byte> in_iter(infile);
    435     istream_iterator<byte> eof;
    436     double temp = 0;
    437     unsigned char c = 0;
    438     while(in_iter != eof)
    439     {
    440         c = *in_iter++;
    441         temp = (double)c/256;
    442         collection.push_back(temp);
    443     }
    444     int amount = collection.size();
    445     double * src = new double[amount];  
    446     size_t j = 0;
    447     for(vector<double>::iterator iter = collection.begin();iter != collection.end();++iter)
    448     {
    449         src[j] = *iter;
    450         j++;
    451     }*/
    452 /*    delete src;
    453     delete fourier;
    454     delete ifourier;
    455 } 
    456 */
    457 
    458 int main(int argc,char **argv)
    459 {
    460     IplImage *img;
    461     if((img = cvLoadImage("F:\Fig0222(a)(face).tif",0))!=0){
    462         int dim = img->imageSize;
    463     //从图像矩阵复制出单维数组;
    464         double * src = new double[dim];
    465         size_t j =0;
    466         for(int y =0;y<img->height;y++)
    467         {
    468             uchar * ptr = (uchar*)(img->imageData + y * img->widthStep);
    469             for(int x =0;x<img->width;x++){
    470                 src[j] = (double)ptr[x]*pow(-1,(double)(x+y))/256;
    471                 j++;
    472             }
    473         }
    474         int w = img->width;
    475         int h = img->height;
    476         int pwid = countPadding(w);
    477         int phei = countPadding(h);
    478         complex<double> *twodfourier = twoDFFT(src,w,h);
    479         double *vals = new double[pwid*phei];
    480         char * pixval = new char[pwid*phei];
    481         CvMat freq;
    482         double max = 0;
    483         double min = 255;
    484         for(size_t p = 0;p<pwid*phei;p++){
    485             vals[p]=log(1+sqrt(pow(twodfourier[p].real(),2.0)+pow(twodfourier[p].imag(),2.0)));//对数级的幅度铺
    486             if(vals[p] > max){
    487                 max = vals[p];
    488             }
    489             if(vals[p] < min){
    490                 min = vals[p];
    491             }
    492         }
    493         cout<<min<< " "<<max<<endl;
    494         for(size_t s = 0;s<pwid*phei;s++){
    495             pixval[s] = (char)((vals[s]-min)/(max-min)*255);
    496         }
    497 /*        for(size_t q = 0;q < pwid*phei;q++){
    498             cout <<vals[q]<<" "<<endl;
    499         }*/
    500         cvInitMatHeader(&freq,pwid,phei,CV_8UC1,pixval);
    501         IplImage *ipl = cvCreateImage(cvGetSize(&freq),8,1);
    502         cvGetImage(&freq,ipl);
    503         complex<double> *twodifourier = twoDIFFT(twodfourier,w,h);
    504         double ipix = 0;
    505         size_t po = 0;
    506         for(int y =0;y<img->height;y++)
    507         {
    508             uchar * ptr = (uchar*)(img->imageData + y * img->widthStep);
    509             for(int x =0;x<img->width;x++){
    510                 ipix = twodifourier[po*pwid+x].real();
    511                 ptr[x] = (uchar)(ipix * 256)*pow(-1,(double)(x+y));
    512             }
    513             po++;
    514         }
    515         cvNamedWindow("frequence domain",CV_WINDOW_AUTOSIZE);
    516         cvShowImage("frequence domain",ipl);
    517         cvNamedWindow("fourier_t",CV_WINDOW_AUTOSIZE);
    518         cvShowImage("fourier_t",img);
    519         cvWaitKey(0);
    520         cvReleaseImage(&ipl);
    521         cvReleaseImage(&img);
    522         cvDestroyWindow("fourier_t");
    523         cvDestroyWindow("frequence domain");
    524         delete vals;
    525         delete pixval;
    526         delete src;
    527         delete twodfourier;
    528         delete twodifourier;
    529         return 1;
    530     }
    531     return 0;
    532 }
    533 
    534 /*
    535 int main()
    536 {
    537     CImg<unsigned char> srcimg("F:\Fig0222(a)(face).tif");
    538     //CImgDisplay main_disp(srcimg,"lina");
    539     srcimg.display();
    540     return 1;
    541 
    542 }
    543 */

     输出:

    原图:

    频谱图:

  • 相关阅读:
    许可和授权的研究及其破解
    Citect:How do I translate Citect error messages?
    异步IO模型和Overlapped结构
    SanDisk SecureAccess™ Software
    Asynchronous socket communication
    一种字节转字符串的语法
    【转载】C# Tutorial
    保存项目文件“XXX.csprj”时出错。类没有注册。
    markdown中的注释
    ubuntu上nginx详细安装部署教程
  • 原文地址:https://www.cnblogs.com/brucemu/p/3369138.html
Copyright © 2011-2022 走看看