DFT,IDFT,FFT,IFFT算法的C++实现

DFT,FFT的算法原理见:https://zh.wikipedia.org/wiki/%E5%BF%AB%E9%80%9F%E5%82%85%E9%87%8C%E5%8F%B6%E5%8F%98%E6%8D%A2

 

#include <iostream>
#include <complex>
#include <cmath>
#include <vector>
#define eps 1e-6 
#define PI 3.14159265354
typedef std::complex<double> complex_t;
using namespace std;
 
//旋转因子的计算 
complex_t W(int k,int n,int N){
	return complex_t(cos(2*PI*k*n/N),-sin(2*PI*k*n/N));
}
 
//格式化 零 
complex_t format(complex_t &c){
	if(fabs(c.real())<eps) c.real()=0;
	if(fabs(c.imag())<eps) c.imag()=0;
	return c;
}
 
double format(double &c){
	if(fabs(c)<eps) c=0;
	return c;
}
 
//离散序列的DFT计算,只针对实数序列 ,完全按照DFT的公式来计算,O(n^2)的复杂度
void DFT(vector<double> &x_n,vector<complex_t> &X_k){
	X_k.clear();
	int N=x_n.size();
	for(int k=0;k<N;++k){
		complex_t t(0,0);
		for(int n=0;n<N;++n){
			t+=x_n[n]*W(k,n,N);
		}
		X_k.push_back(format(t));
	}
	
	int cnt=0;
	for(int i=0;i<N;++i){
		if(cnt==(int)sqrt(N)){
			cout<<endl;
			cnt=0;
		}
		++cnt;
		cout<<format(X_k[i])<<" ";
	}
	cout<<endl;
	
}
 
//IDFT的计算,只针对实数序列  
void IDFT(vector<complex_t> &X_k,vector<double> &x_n){
	x_n.clear();
	int N=X_k.size();
	for(int n=0;n<N;++n){
		complex_t t(0,0);
		for(int k=0;k<N;++k){
			t+=X_k[k]*W(k,-n,N);
		}
		x_n.push_back(t.real()/N);//运算结果只剩下实部 
		//cout<<(t/(double)N)<<endl; 
	}
	int cnt=0;
	for(int i=0;i<N;++i){
		if(cnt==(int)sqrt(N)){
			cout<<endl;
			cnt=0;
		}
		++cnt;
		cout<<format(x_n[i])<<" ";
	}
	cout<<endl;
	
}
 
void DFT_test(){
	int N=64;
	vector<double> x_n(N);
	vector<complex_t> X_k(N);
	for(int i=0;i<N;++i){
		x_n[i]=i;
	}
	DFT(x_n,X_k);
	IDFT(X_k,x_n);
}
 
 
//保证N是2的n次幂
int bitlen(int N){
	int n=0;
	while((N&1)==0){
		n++;
		N>>=1;
	}
	return n;
}
 
 
int reverse_bit(int n,int len){//bit反转 
	int tmp=0;
	while(len--){
		tmp+=((n&1)<<len);
		n>>=1;
	}
	return tmp;
 
}
 
//序数重排 
void resort(vector<complex_t> &x_n,int N){
	vector<complex_t> v(x_n);
	int len=bitlen(N);
	for(int i=0;i<N;++i){
		x_n[i]=v[reverse_bit(i,len)];
	}
}
 
 
//基2,FFT算法实现,O(nlogn)的复杂度
void FFT(vector<complex_t> &x_n){
	int N=x_n.size();
	int r=bitlen(N);
	
	vector<complex_t> W(N);
 
	//预先计算旋转因子 
	for(int i=0;i<N;++i){
		double angle=-i*2*PI/N;
		W[i]=complex_t(cos(angle),sin(angle));
	}
	
	
	for(int k=0;k<r;++k){//迭代次数 
		for(int j=0;j<(1<<k);++j){
			int butterfly=1<<(r-k);
			int p=j*butterfly;
			int s=p+butterfly/2;
			for(int i=0;i<butterfly/2;++i){
				complex_t c=x_n[i+p]+x_n[i+s];
				x_n[i+s]=(x_n[i+p]-x_n[i+s])*W[i*(1<<k)];
				x_n[i+p]=c;
			}
		}
	}
	
	//次序重排 
	resort(x_n,N);
	int cnt=0;
	for(int i=0;i<N;++i){
		if(cnt==(int)sqrt(N)){
			cout<<endl;
			cnt=0;
		}
		++cnt;
		cout<<format(x_n[i])<<" ";
		
	}
	cout<<endl;
}
 
//IFFT,与FFT基本一致 
void IFFT(vector<complex_t> &x_n){
	int N=x_n.size();
	int r=bitlen(N);
	
	vector<complex_t> W(N);
 
	//预先计算旋转因子 
	for(int i=0;i<N;++i){
		double angle=i*2*PI/N;//IFFT的旋转因子与FFT的旋转因子差一个负号 
		W[i]=complex_t(cos(angle),sin(angle));
	}
	
	
	for(int k=0;k<r;++k){//迭代次数 
		for(int j=0;j<(1<<k);++j){
			int butterfly=1<<(r-k);
			int p=j*butterfly;
			int s=p+butterfly/2;
			for(int i=0;i<butterfly/2;++i){
				complex_t c=x_n[i+p]+x_n[i+s];
				x_n[i+s]=(x_n[i+p]-x_n[i+s])*W[i*(1<<k)];
				x_n[i+p]=c;
			}
		}
	}
	
	//次序重排 
	resort(x_n,N);
	int cnt=0;
	for(int i=0;i<N;++i){
		if(cnt==(int)sqrt(N)){
			cout<<endl;
			cnt=0;
		}
		++cnt;
		x_n[i]/=N;//IFFT与FFT还差一个系数 
		cout<<format(x_n[i])<<" ";
	}
	cout<<endl;
}
 
void FFT_test(){
	int N=64;
	vector<complex_t> x_n;
	complex_t c(0,0);
	for(int i=0;i<N;++i){
		c.real()=i;
		x_n.push_back(c);
	}
	
	FFT(x_n);
	IFFT(x_n);
}
 
 
int main(){
	DFT_test();
	cout<<endl;
	FFT_test();
	return 0;
}


运行结果与Python的scipy库中的fft算法运行结果对比,基本验证了该算法的正确性:

  • 4
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
C++实现图像匹配FFT算法的代码如下: ```cpp #include <iostream> #include <opencv2/opencv.hpp> #include <opencv2/imgproc/imgproc.hpp> using namespace std; using namespace cv; int main(int argc, char** argv) { if (argc != 3) { cout << "Usage: " << argv << " <src image> <template image>" << endl; return -1; } Mat srcImage = imread(argv, IMREAD_GRAYSCALE); Mat tplImage = imread(argv, IMREAD_GRAYSCALE); if (srcImage.empty() || tplImage.empty()) { cout << "Read image error!" << endl; return -1; } // 傅里叶变换 Mat fftSrc, fftTpl; cv::dft(srcImage, fftSrc, cv::DFT_COMPLEX_OUTPUT); cv::dft(tplImage, fftTpl, cv::DFT_COMPLEX_OUTPUT); // 傅里叶变换的结果需要进行中心化 cv::fftShift(fftSrc, fftSrc); cv::fftShift(fftTpl, fftTpl); // 求互相关 Mat ifft; cv::mulSpectrums(fftSrc, fftTpl, ifft, 0, true); cv::idft(ifft, ifft, cv::DFT_SCALE | cv::DFT_REAL_OUTPUT); // 找到最大值点 Point maxLoc; cv::minMaxLoc(ifft, NULL, NULL, NULL, &maxLoc); // 绘制矩形框 rectangle(srcImage, maxLoc, Point(maxLoc.x + tplImage.cols, maxLoc.y + tplImage.rows), Scalar(0, 0, 255), 2); imshow("src", srcImage); waitKey(0); return 0; } ``` 其中,src image是原始图像,template image是要匹配的模板图像。在程序中,首先读取这两个图像,并进行灰度化处理。然后分别对它们进行傅里叶变换,并进行中心化操作。接下来,对它们进行互相关,找到最大值点,并在原始图像上绘制矩形框。 相关问题: 1. 什么是FFT算法? 2. 傅里叶变换的作用是什么? 3. 如何求两幅图像的互相关?

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值