C++ 离散傅里叶变换
一、序言:
该教程基于之前的图像处理类MYCV,是对其的补充。
二、设计目标
对图像进行简单的离散傅里叶变换,并输出生成的频谱图。
三、需要提前掌握的知识
二维傅里叶变换公式:
四、详细步骤
1.首先定义一个方法,该方法对输入的图像进行傅里叶变换
输入:MyImage 源图像
输出:ComplexNu 进行离散傅里叶变换后的复数数组
定义:
static ComplexNumber* Dft2(MyImage const &Scr);
实现:
1 ComplexNumber* MyCV::Dft2(MyImage const &Scr) 2 { 3 int width = Scr.m_width; 4 int height = Scr.m_height; 5 6 // 将 scr_data 转化为灰度 7 MyImage *grayimage = Gray(Scr); 8 unsigned char* gray_data = grayimage->m_data; 9 int gray_bytesPerLine = grayimage->m_bytesPerLine; 10 11 // 将 gray_data 转化为 double 型,并去掉用于填充的多余空间 12 double *double_data = new double[width*height]; 13 14 for(int i=0;i) 15 for(int j=0;j) 16 { 17 double_data[i*width+j]=(double)gray_data[i*gray_bytesPerLine+j]; 18 } 19 20 // 对 double_data 进行傅里叶变换 21 ComplexNumber *dft2_data = new ComplexNumber[width*height]; 22 double fixed_factor_for_axisX = (-2 * PI) / height; 23 // evaluate -i2π/N of -i2πux/N, and store the value for computing efficiency 24 double fixed_factor_for_axisY = (-2 * PI) / width; 25 // evaluate -i2π/N of -i2πux/N, and store the value for computing efficiency 26 27 for (int u = 0; u ) { 28 for (int v = 0; v ) { 29 for (int x = 0; x ) { 30 for (int y = 0; y ) { 31 double powerX = u * x * fixed_factor_for_axisX; // evaluate -i2πux/N 32 double powerY = v * y * fixed_factor_for_axisY; // evaluate -i2πux/N 33 ComplexNumber cplTemp; 34 cplTemp.m_rl = double_data[y + x*width] * cos(powerX + powerY); 35 // evaluate f(x) * e^(-i2πux/N), which is equal to f(x) * (cos(-i2πux/N)+sin(-i2πux/N)i) according to Euler's formula 36 cplTemp.m_im = double_data[y + x*width] * sin(powerX + powerY); 37 dft2_data[v + u*width] = dft2_data[v + u*width] + cplTemp; 38 } 39 } 40 } 41 } 42 43 // 返回傅里叶数组 44 return dft2_data; 45 }
2.为了让傅里叶变换可视化,旭阳对其进行标准化和中性化
输入:ComplexNumber 离散傅里叶变换生成的复数数组
输出:MyImage 可视化后的图像
定义:
static MyImage* Dft22MyImage(ComplexNumber *Scr,int width,int height);
实现:
1 MyImage* MyCV::Dft22MyImage(ComplexNumber *Scr, int const width, int const height) 2 { 3 // 将傅里叶数组归一化 4 // 取模 5 double mold[width*height]; 6 for(int i = 0 ;i) 7 { 8 mold[i] = Scr[i].get_mold(); 9 } 10 11 // 获取最小值 12 double min = mold[0]; 13 for(int i = 0;i) 14 { 15 if(mold[i]<min) 16 min = mold[i]; 17 } 18 19 // 获取去掉前几大值的最大值 20 double maxqueue[20] = {0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.},max; 21 22 for(int i = 0;i ){ 23 if(mold[i]>maxqueue[0]) 24 maxqueue[0] = mold[i]; 25 } 26 27 for(int j =1;j<20;j++){ 28 for(int i = 0;i ){ 29 if(mold[i]>maxqueue[j]&&mold[i] 1]) 30 maxqueue[j] = mold[i]; 31 } 32 } 33 34 max = maxqueue[19]; 35 36 unsigned char *normalized_data = new unsigned char[width*height]; 37 38 for(int i=0;i ) 39 for(int j=0;j ) 40 { 41 unsigned char t = (unsigned char)((mold[i*width+j]-min)/(max-min)*255); 42 if(t>255) 43 t = 255; 44 normalized_data[i*width+j]=t; 45 } 46 47 // 将图像中心化 48 unsigned char* center_data = new unsigned char[width*height]; 49 50 for (int u = 0; u ){ 51 for (int v = 0; v ) { 52 if ((u<(height / 2)) && (v<(width / 2))) { 53 center_data[v + u*width] = 54 normalized_data[width / 2 + v + (height / 2 + u)*width]; 55 } 56 else if ((u<(height / 2)) && (v >= (width / 2))) { 57 center_data[v + u*width] = 58 normalized_data[(v - width / 2) + (height / 2 + u)*width]; 59 } 60 else if ((u >= (height / 2)) && (v<(width / 2))) { 61 center_data[v + u*width] = 62 normalized_data[(width / 2 + v) + (u - height / 2)*width]; 63 } 64 else if ((u >= (height / 2)) && (v >= (width / 2))) { 65 center_data[v + u*width] = 66 normalized_data[(v - width / 2) + (u - height / 2)*width]; 67 } 68 } 69 } 70 71 // 向中心化的数组填充空间 72 int bytesPerLine = (width*8+31)/32*4; 73 unsigned char *dst_data = new unsigned char[bytesPerLine*height]; 74 75 for(int i=0;i ) 76 for(int j=0;j ) 77 { 78 dst_data[i*bytesPerLine+j] = center_data[i*width+j]; 79 } 80 81 return new MyImage(dst_data,width,height,MyImage::format::GRAY8); 82 }
至此,离散傅里叶变换的方法实现完成,效果图如下: