木柴

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

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的高斯滤波后的频谱图;

posted on 2013-10-16 14:19  木柴  阅读(1098)  评论(0编辑  收藏  举报