• 二维离散傅立叶变换图像频域处理


    vc++实现的傅立叶变换,参考算法导论中的快速傅立叶算法,使用openCV做图像的读入与显示,加入了高斯函数低通滤波;

      1 /************************************************************
      2 *二维离散傅立叶变换和滤波函数(高斯低通)的实现
      3 *用于计算图像离散序列的傅立叶频谱图,并用于频域图像处理
      4 *算法:多项式快速傅立叶算法(蝶形) 理论基础:算法导论,图像处理
      5 *时间复杂度:一维O(NlogN),二维O(N^2)
      6 *工具:openCV读取图像与展示效果
      7 *版本:测试
      8 *@auto:Bruce mu
      9 ************************************************************/
     10 #include <stdio.h>
     11 #include <iostream>
     12 #include <complex>
     13 #include <bitset>
     14 #include <fstream>
     15 #include <algorithm>
     16 #include <iterator>
     17 #include <math.h>
     18 #include "cv.h"
     19 #include "highgui.h"
     20 #include "CImg.h"
     21 #define pi 3.1415926535
     22 #define DELTA 5.0
     23 using std::iostream;
     24 using std::bitset;
     25 using std::complex;
     26 using namespace std;
     27 using namespace cimg_library;
     28 
     29 /*******为自底向上的迭代重排序列计算位置************/
     30 int rev(int k,int n)
     31 {
     32      bitset<32> tmp(k);
     33      bitset<32> dist;
     34      for(int m = 0;m<n;m++)
     35      {
     36         if(tmp.test(m))
     37         {
     38             dist.set(n-1-m);
     39         }
     40      }
     41      int revk = (int)dist.to_ulong();
     42      return revk;
     43 }
     44 //重载形式
     45 complex<double>* FFT(const complex<double> *srcimg,int n)
     46 {
     47     double flag = log10((double)n)/log10(2.0);
     48     int N = n;
     49     if(flag - (int)flag != 0){   //判断是否为2的指数次
     50         cout <<"the length of srcimg is wrong"<< endl;
     51         /*填充成2的指数项*/
     52         cout <<"need padding"<<endl;
     53         N = pow(2,(double)((int)flag+1));
     54         flag = log10((double)N)/log10(2.0);
     55     }
     56     /*改变成奇偶顺序*/
     57     complex<double> *arr= new complex<double>[N];
     58     int sub;
     59     for(int k =0;k<N;k++)
     60     {
     61         sub =rev(k,(int)flag); 
     62         if(sub <= n-1){
     63             arr[k] = *(srcimg + sub);
     64         }else{
     65             complex<double> t = complex<double>(0,0);
     66             arr[k] = t;
     67         }
     68     }
     69      for(int s =1;s <= flag;s++)
     70     {
     71         int m = pow(2,(double)s);
     72         complex<double> wm = complex<double>(cos(2*pi/m),sin(2*pi/m));//wm1:从W21开始,周期变换
     73         for(int p = 0;p<N;p+=m)
     74         {
     75             complex<double> w(1,0);
     76             for(int j = 0;j<=m/2-1;j++)
     77             {
     78                 complex<double> t = w * arr[p+j+m/2];
     79                 complex<double> u = arr[p+j];
     80                 arr[p+j] = u+t;
     81                 arr[p+j+m/2] = u-t;
     82                 w = w*wm;
     83             }
     84         }
     85     }
     86     return arr;
     87 }
     88 /***********一维快速傅立叶变换********************
     89 *srcimg : 原始一维序列                          *
     90 *n     :一维序列的长度
     91 *************************************************/
     92 complex<double>* FFT(const double *srcimg,int n)
     93 {
     94     double flag = log10((double)n)/log10(2.0);
     95     int N = n;
     96     if(flag - (int)flag != 0){   //判断是否为2的指数次
     97 //        cout <<"the length of srcimg is wrong"<< endl;
     98         /*填充成2的指数项*/
     99 //        cout <<"need padding"<<endl;
    100         N = pow(2,(double)((int)flag+1));
    101         flag = log10((double)N)/log10(2.0);
    102     }
    103     /*改变成奇偶顺序*/
    104     complex<double> *arr= new complex<double>[N];
    105     int sub;
    106     for(int k =0;k<N;k++)
    107     {
    108         sub =rev(k,(int)flag); 
    109         if(sub <= n-1){
    110             arr[k] = complex<double>(*(srcimg + sub),0);
    111         }else{
    112             complex<double> t = complex<double>(0,0);
    113             arr[k] = t;
    114         }
    115     }
    116 //    cout<<"------------after padding and retrival-----------------"<<endl;
    117 //    for(size_t y=0;y<N;y++)
    118 //    {
    119 //        cout << arr[y].real()<<"  "<<arr[y].imag()<<endl;
    120 //    }
    121     /*基于迭代的蝶形快速傅立叶变换,自底向上*/
    122      for(int s =1;s <= flag;s++)
    123     {
    124         int m = pow(2,(double)s);
    125         complex<double> wm = complex<double>(cos(2*pi/m),sin(2*pi/m));//wm1:从W21开始,周期变换
    126         for(int p = 0;p<N;p+=m)
    127         {
    128             complex<double> w(1,0);
    129             for(int j = 0;j<=m/2-1;j++)
    130             {
    131                 complex<double> t = w * arr[p+j+m/2];
    132                 complex<double> u = arr[p+j];
    133                 arr[p+j] = u+t;
    134                 arr[p+j+m/2] = u-t;
    135                 w = w*wm;
    136             }
    137         }
    138     }
    139     return arr;
    140 }
    141 
    142 int countPadding(int n);
    143 /*****************一维快速傅立叶逆变换********************/
    144 /*fftimg:原始一维傅立叶序列
    145   n     : 序列长度
    146 *******************************************************/
    147 complex<double>* IFFT(const complex<double> *fftimg,int n)
    148 {
    149     n = countPadding(n);
    150     double flag = log10((double)n)/log10(2.0);
    151     int N = n;
    152     if(flag - (int)flag != 0){   //判断是否为2的指数次
    153         cout <<"the length of srcimg is wrong"<< endl;
    154         /*填充成2的指数项*/
    155         cout <<"need padding"<<endl;
    156         N = pow(2,(double)((int)flag+1));
    157         flag = log10((double)N)/log10(2.0);
    158     }
    159     /*改变成奇偶顺序*/
    160     complex<double> * spit = new complex<double>[N];
    161     int sub=0;
    162     for(int k =0;k<N;k++)
    163     {
    164         sub =rev(k,(int)flag); 
    165         if(sub < n){
    166             spit[k] = complex<double>(*(fftimg + sub));
    167         }else{
    168             spit[k] = complex<double>(0,0);
    169         }
    170     }
    171 
    172     for(int s =1;s <= flag;s++)
    173     {
    174         int m = pow(2,(double)s);
    175         complex<double> wm = complex<double>(cos(-2*pi/m),sin(-2*pi/m));//wm1:从W2(-1)开始
    176         for(int p = 0;p<N;p+=m)
    177         {
    178             complex<double> w(1,0);
    179             for(int j = 0;j<=m/2-1;j++)
    180             {
    181                 complex<double> t = w * spit[p+j+m/2];
    182                 complex<double> u = spit[p+j];
    183                 spit[p+j] = u+t;
    184                 spit[p+j+m/2] = u-t;
    185                 w = w*wm;
    186             }
    187         }
    188     }
    189 
    190     for(size_t p =0;p<n;p++)
    191     {
    192         spit[p] = spit[p]/complex<double>(N,0);
    193     }
    194     return spit;
    195 }
    196   
    197 /*******使用共轭的快速傅立叶逆变换**************/
    198 complex<double>* IFFT2(const complex<double> *fftimg,int n)
    199 {
    200     n = countPadding(n);
    201     complex<double> *gfftimg = new complex<double>[n];
    202     for(size_t i = 0;i<n;i++){
    203         gfftimg[i] = complex<double>(fftimg[i].real(),-fftimg[i].imag());
    204     }
    205     complex<double> *ifft = FFT(gfftimg,n); 
    206     for(size_t j = 0;j<n;j++)
    207     {
    208         ifft[j] = ifft[j]/complex<double>(n,0);
    209     }
    210     delete gfftimg;
    211     return ifft;
    212 }
    213 
    214 /*************二维快速傅立叶变换**************************
    215 *srcimg: 用一维表示的二维原始序列
    216 *width :宽度
    217 *height:高度
    218 ********************************************************/
    219 complex<double>* twoDFFT(const double *srcimg,int width,int height)
    220 {
    221     int w = countPadding(width);
    222     int h = countPadding(height);
    223     int pixes = w * h;
    224     complex<double> *hdirection = new complex<double>[w];
    225     complex<double> *vdirection = new complex<double>[h];
    226     complex<double> *fourier = new complex<double>[pixes];
    227     /*二维水平方向*/
    228     for(size_t i = 0;i<h;i++){
    229         for(size_t j = 0;j<w;j++){
    230             if(i>=height || j >=width){
    231                 hdirection[j] = complex<double>(0,0);
    232             }else{
    233                 hdirection[j] = complex<double>(srcimg[i*width + j],0);
    234             }
    235     //        cout << hdirection[j] << " ";
    236         }
    237     //    cout <<""<<endl;
    238         complex<double> *hfourier = FFT(hdirection,w);
    239         for(size_t m = 0;m<w;m++){
    240             fourier[i*w+m] = hfourier[m];
    241         }
    242         delete hfourier;
    243     }
    244     /*二维垂直方向*/
    245     for(size_t ii = 0;ii<w;ii++){
    246         for(size_t jj = 0;jj<h;jj++){
    247             vdirection[jj] = fourier[jj*w + ii];
    248         }
    249         complex<double> *vfourier = FFT(vdirection,h);
    250         for(size_t mm = 0;mm < h;mm++){
    251             fourier[mm*w +ii] = vfourier[mm];
    252         }
    253         delete vfourier;
    254     }
    255     delete hdirection;
    256     delete vdirection;
    257     return fourier;
    258 
    259 }
    260 /**************二维快速傅立叶逆变换*************************
    261 *fourier : 一维表示的二维傅立叶变换序列                     *
    262 *width   :宽                                             *
    263 *height  :高                                             *
    264 ***********************************************************/
    265 complex<double>* twoDIFFT(const complex<double> *fourier,int width,int height)
    266 {
    267     width = countPadding(width);
    268     height = countPadding(height);
    269     int fpoints = width * height;
    270     complex<double> *hdirection = new complex<double>[width];
    271     complex<double> *vdirection = new complex<double>[height];
    272     complex<double> *ifourier = new complex<double>[fpoints];
    273 
    274     for(size_t ii = 0;ii<height;ii++)
    275     {
    276         for(size_t jj = 0;jj<width;jj++){
    277             hdirection[jj] = fourier[ii*width+jj];
    278         }
    279         complex<double> *hifour = IFFT(hdirection,width);//临时变量
    280         for(size_t mm = 0;mm<width;mm++){
    281             ifourier[ii*width+mm] = hifour[mm];
    282         }
    283         delete hifour;
    284     }
    285     for(size_t i = 0;i<width;i++){
    286         for(size_t j = 0;j<height;j++){
    287             vdirection[j] = ifourier[j*width+i];
    288         }
    289         complex<double> *vifour = IFFT(vdirection,height);
    290         for(size_t m = 0;m<height;m++){
    291             ifourier[m*width+i] = vifour[m];
    292         }
    293         delete vifour;
    294     }    
    295     delete hdirection;
    296     delete vdirection;
    297     return ifourier;
    298 }
    299 /******************计算填充数********************************************
    300 *蝶形傅立叶变换算法只计算2的指数次的离散序列,对于非2的指数次的序列,使用零填充*
    301 ***********************************************************************/
    302 inline int countPadding(int n)
    303 {
    304     double lg = log10((double)n)/log10(2.0);
    305     if((lg - (int)lg) == 0){
    306         return n;
    307     }
    308     int N = pow(2.0,((int)lg+1));
    309     return N;
    310 }
    311 
    312 /*****高斯低通滤波函数*************************
    313 *src:   输入频谱
    314 *width: 输入频谱宽度
    315 *height:输入频谱高度
    316 *D:     高斯函数方差,即滤波阈值
    317 *只对于移位居中后的傅立叶频谱进行高斯低通滤波
    318 */
    319 void guass(complex<double> *src,int width,int height,double D)
    320 {
    321     //find centre point
    322     int orgx = floor(width/2.0);
    323     int orgy = floor(height/2.0);
    324     double distence = 0;
    325     for(size_t i = 0;i<height;i++)
    326     {
    327         for(size_t j = 0;j<width;j++)
    328         {
    329             distence = sqrt(pow(abs((int)(i-orgy)),2.0)+pow(abs((int)(j-orgx)),2.0));
    330             src[i*width+j] = src[i*width+j] * exp(-distence/(2*pow(D,2.0)));
    331             
    332         }
    333         //cout<<i<<" "<<distence<<" "<<endl;
    334         
    335     }
    336 //    cout<<orgx<<" "<<orgy<<endl;
    337 }
    338 /************复数傅立叶频谱数组转换成256级灰度数组*****************/
    339 void toGray(complex<double> *twodfourier,int pwid,int phei,char* pixval)
    340 {
    341         double *vals = new double[pwid*phei];
    342         double max = 0;
    343         double min = 255;
    344         for(size_t p = 0;p<pwid*phei;p++){
    345             vals[p]=log(1+sqrt(pow(twodfourier[p].real(),2.0)+pow(twodfourier[p].imag(),2.0)));//对数级的幅度铺
    346             if(vals[p] > max){
    347                 max = vals[p];
    348             }
    349             if(vals[p] < min){
    350                 min = vals[p];
    351             }
    352         }
    353         cout<<min<< " "<<max<<endl;
    354         cout<<pwid<<" "<<phei<<endl;
    355         for(size_t s = 0;s<pwid*phei;s++){
    356             pixval[s] = (char)((vals[s]-min)/(max-min)*255);
    357         }
    358         delete vals;
    359 }
    360 /******************opencv 读取图像与展示效果***********************/
    361 int main(int argc,char **argv)
    362 {
    363     IplImage *img;
    364     if((img = cvLoadImage("F:\Fig0222(a)(face).tif",0))!=0){
    365         int dim = img->imageSize;
    366         //从图像矩阵复制出单维数组,并做频谱居中操作,对应改写接口,返回单维数组;
    367         double * src = new double[dim];
    368         size_t j =0;
    369         for(int y =0;y<img->height;y++)
    370         {
    371             uchar * ptr = (uchar*)(img->imageData + y * img->widthStep);
    372             for(int x =0;x<img->width;x++){
    373                 /***输入函数乘以(-1)的(x+y)次方,频谱将居中*/
    374                 src[j] = (double)ptr[x]*pow(-1,(double)(x+y))/256;
    375                 j++;
    376             }
    377         }
    378         int w = img->width;
    379         int h = img->height;
    380         int pwid = countPadding(w);
    381         int phei = countPadding(h);
    382 
    383         complex<double> *twodfourier = twoDFFT(src,w,h);
    384         char * pixval = new char[pwid*phei];
    385         CvMat freq;
    386         toGray(twodfourier,pwid,phei,pixval);//复数频谱转256灰度
    387         cvInitMatHeader(&freq,pwid,phei,CV_8UC1,pixval);
    388         IplImage *ipl = cvCreateImage(cvGetSize(&freq),8,1);
    389         cvGetImage(&freq,ipl);//获取频谱图像
    390 
    391         guass(twodfourier,pwid,phei,DELTA);//方差DELTA的高斯平滑(高斯低通滤波)
    392         CvMat gaufre;
    393         char *pixvals = new char[pwid*phei];
    394         toGray(twodfourier,pwid,phei,pixvals);
    395         cvInitMatHeader(&gaufre,pwid,phei,CV_8UC1,pixvals);
    396         IplImage *gausf = cvCreateImage(cvGetSize(&gaufre),8,1);
    397         cvGetImage(&gaufre,gausf);//高斯平滑后的频谱图像
    398 
    399         complex<double> *twodifourier = twoDIFFT(twodfourier,w,h);
    400         double ipix = 0;
    401         size_t po = 0;
    402         for(int y =0;y<img->height;y++)
    403         {
    404             uchar * ptr = (uchar*)(img->imageData + y * img->widthStep);
    405             for(int x =0;x<img->width;x++){
    406                 ipix = twodifourier[po*pwid+x].real();
    407                 ptr[x] = (uchar)(ipix * 256)*pow(-1,(double)(x+y));
    408             }
    409             po++;
    410         }
    411         cvNamedWindow("frequence_domain",CV_WINDOW_AUTOSIZE);
    412         cvShowImage("frequence_domain",ipl);
    413         cvNamedWindow("gauss_fre",CV_WINDOW_AUTOSIZE);
    414         cvShowImage("gauss_fre",gausf);
    415         cvNamedWindow("fourier_t",CV_WINDOW_AUTOSIZE);
    416         cvShowImage("fourier_t",img);
    417         cvWaitKey(0);
    418         cvReleaseImage(&ipl);
    419         cvReleaseImage(&gausf);
    420         cvReleaseImage(&img);
    421         cvDestroyWindow("fourier_t");
    422         cvDestroyWindow("frequence_domain");
    423         cvDestroyWindow("gauss_fre");
    424         delete pixval;
    425         delete pixvals;
    426         delete src;
    427         delete twodfourier;
    428         delete twodifourier;
    429         return 1;
    430     }
    431     return 0;
    432 }

    显示输出:

    原图

        A     B

    C

    D

    A为原图,B为使用均值为0,方差为5.0的高斯函数做低通滤波后的效果图。C为原图的傅立叶频谱图(已居中显示),D为使用方差5.0的高斯滤波后的频谱图;

  • 相关阅读:
    Hadoop IO
    HDFS
    简介
    队列
    classLoader和Class.forName的区别
    String为什么是final类型的
    Fabric
    超级账本——面向企业的分布式账本
    以太坊
    pycharm破解教程
  • 原文地址:https://www.cnblogs.com/brucemu/p/3372157.html
Copyright © 2020-2023  润新知