图像的Fourier变换

原理性快速傅里叶变换代码!

一维FFT--->>>二维FFT!

图像的频率是表征图像中灰度变化剧烈程度的指标,是灰度在平面空间上的梯度.在噪声点和图像边缘处的频率为高频。实际上对图像进行二维傅立叶变换得到频谱图,就是图像梯度的分布图,当然频谱图上的各点与图像上各点并不存在一一对应的关系,即使在不移频的情况下也是没有。傅立叶频谱图上我们看到的明暗不一的亮点,实际上图像上某一点与邻域点差异的强弱,即梯度的大小,也即该点的频率的大小。图像的能量分布,如果频谱图中暗的点数更多,那么实际图像是比较柔和的(因为各点与邻域差异都不大,梯度相对较小),反之,如果频谱图中亮的点数多,那么实际图像一定是尖锐的,边界分明且边界两边像素差异较大的。

图像中的每个点通过傅里叶变换都成了谐波函数的组合,也就有了频率,这个频率则是在这一点上所有产生这个灰度的频率之和,也就是说傅里叶变换可以将这些频率分开来。当想除去图像背景时,只要去掉背景的频率就可以了。

#define PI 3.1415926535

#include <cv.h>
#include <highgui.h>
#include <complex>


using namespace std;
using namespace cv;


void FFT(complex<double>* TD,complex<double>* FD,int r);
bool Fourier(IplImage* src,IplImage*dst,int width,int height);


int main()
{
IplImage* src=cvLoadImage("1.bmp",0);
IplImage* dst=cvCreateImage(cvGetSize(src),src->depth,src->nChannels);
Fourier(src,dst,src->width,src->height);
cvSaveImage("1Fourier.bmp",dst);
return 0;
}


/*****************************************************************************
*void FFT(complex<double>* TD,complex<double>* FD,int r)
*参数:
* int* TD--指向时域数组的指针
* int* FD--指向频域数组的指针
* r   --2的幂数,即迭代次数
* (r为log2N,傅里叶的点数N可以由r求出,即将1左移r位)
******************************************************************************/
void FFT(complex<double>* TD,complex<double>* FD,int r)
{
int N; 傅里叶点数(多少级蝶形运算)
N=1<<r; 将1左移r位
complex<double> *W=new complex<double>[N/2];///加权系数(complex是复数)
complex<double> *X1=new complex<double>[N];
complex<double> *X2=new complex<double>[N];
///计算加权系数
for (int i=0;i<N/2;i++)
{
double angle=-i*PI*2/N;
W[i]=complex<double>(cos(angle),sin(angle));
}
//将时域点写入X1
memcpy(X1,TD,sizeof(complex<double>) *N);
//采用蝶形算法进行FFT
for (int k=0;k<r;k++) //进行第几级运算
{
for (int j=0;j<1<<k;j++) /当前所有的蝶形开始运算
{
int bfsize=1<<(r-k);
for (int i=0;i<bfsize/2;i++) 相邻蝶形运算
{
int p=j*bfsize;
X2[i+p]=X1[i+p] + X1[i+p+bfsize/2];
X2[i+p+bfsize/2]=(X1[i+p]-X1[i+p+bfsize/2])*W[i*(1<<k)];
}
}
complex<double>* X=X1;
X1=X2;
X2=X;
}
重新排序
for (int j=0;j<N;j++)
{
int p=0;
for (int i=0;i<r;i++)
{
if (j&(1<<i))
{
p+=1<<(r-i-1);
}
}
FD[j]=X1[p];
}
//释放内存
delete W;
delete X1;
delete X2;
}


bool Fourier(IplImage* src,IplImage*dst,int width,int height)
{
/傅里叶的宽、高为2的整数次方(FFT)
int w=1,h=1;
int wp=0,hp=0;/2的幂次数,即迭代次数
/计算进行傅里叶变换的宽度和高度(2的整数次方)
while (w*2<=width)
{
w*=2;
wp++;
}
while (h*2<=height)
{
h*=2;
hp++;
}
//分配内存
complex<double> *TD=new complex<double>[w*h];
complex<double> *FD=new complex<double>[w*h];

for (int i=0;i<h;i++)行
{
for (int j=0;j<w;j++)列
{
int pixel=((uchar*)src->imageData+i*src->widthStep)[j];
//给时域赋值
TD[j+w*i]=complex<double>(pixel,0);
}
}
//对y方向进行FFT
for (int i=0;i<h;i++)
{
FFT(&TD[w*i],&FD[w*i],wp);
}
保存变换结果
for (int i=0;i<h;i++)
{
for (int j=0;j<w;j++)
{
TD[i+h*j]=FD[j+w*i];
}
}
//对x方向进行FFT
for (int i=0;i<w;i++)
{
FFT(&TD[i*h],&FD[i*h],hp);
}
for (int i=0;i<h;i++)
{
for (int j=0;j<w;j++)
{
计算频谱
double temp=sqrt(FD[j*h+i].real()*FD[j*h+i].real()+
FD[j*h+i].imag()*FD[j*h+i].imag())/100;
if (temp>255)
{
temp=255;判断超过255,直接赋值为255
}
//指向第(i<h/2?i+h/2:i-h/2)行,第j<w/2?j+w/2:j-w/2个像素的指针
//不直接取i和j,是为了将变换后的原点移动到中心
((uchar*)dst->imageData+(i<h/2?i+h/2:i-h/2)*dst->widthStep)[j<w/2?j+w/2:j-w/2]=temp;
}
}
/删除临时变量
delete TD;
delete FD;
return true;
}#define PI 3.1415926535
#include <cv.h>
#include <highgui.h>
#include <complex>


using namespace std;
using namespace cv;


void FFT(complex<double>* TD,complex<double>* FD,int r);
bool Fourier(IplImage* src,IplImage*dst,int width,int height);


int main()
{
IplImage* src=cvLoadImage("1.bmp",0);
IplImage* dst=cvCreateImage(cvGetSize(src),src->depth,src->nChannels);
Fourier(src,dst,src->width,src->height);
cvSaveImage("1Fourier.bmp",dst);
return 0;
}


/*****************************************************************************
*void FFT(complex<double>* TD,complex<double>* FD,int r)
*参数:
* int* TD--指向时域数组的指针
* int* FD--指向频域数组的指针
* r   --2的幂数,即迭代次数
* (r为log2N,傅里叶的点数N可以由r求出,即将1左移r位)
******************************************************************************/
void FFT(complex<double>* TD,complex<double>* FD,int r)
{
int N; 傅里叶点数(多少级蝶形运算)
N=1<<r; 将1左移r位
complex<double> *W=new complex<double>[N/2];///加权系数(complex是复数)
complex<double> *X1=new complex<double>[N];
complex<double> *X2=new complex<double>[N];
///计算加权系数
for (int i=0;i<N/2;i++)
{
double angle=-i*PI*2/N;
W[i]=complex<double>(cos(angle),sin(angle));
}
//将时域点写入X1
memcpy(X1,TD,sizeof(complex<double>) *N);
//采用蝶形算法进行FFT
for (int k=0;k<r;k++) //进行第几级运算
{
for (int j=0;j<1<<k;j++) /当前所有的蝶形开始运算
{
int bfsize=1<<(r-k);
for (int i=0;i<bfsize/2;i++) 相邻蝶形运算
{
int p=j*bfsize;
X2[i+p]=X1[i+p] + X1[i+p+bfsize/2];
X2[i+p+bfsize/2]=(X1[i+p]-X1[i+p+bfsize/2])*W[i*(1<<k)];
}
}
complex<double>* X=X1;
X1=X2;
X2=X;
}
重新排序
for (int j=0;j<N;j++)
{
int p=0;
for (int i=0;i<r;i++)
{
if (j&(1<<i))
{
p+=1<<(r-i-1);
}
}
FD[j]=X1[p];
}
//释放内存
delete W;
delete X1;
delete X2;
}


bool Fourier(IplImage* src,IplImage*dst,int width,int height)
{
/傅里叶的宽、高为2的整数次方(FFT)
int w=1,h=1;
int wp=0,hp=0;/2的幂次数,即迭代次数
/计算进行傅里叶变换的宽度和高度(2的整数次方)
while (w*2<=width)
{
w*=2;
wp++;
}
while (h*2<=height)
{
h*=2;
hp++;
}
//分配内存
complex<double> *TD=new complex<double>[w*h];
complex<double> *FD=new complex<double>[w*h];

for (int i=0;i<h;i++)行
{
for (int j=0;j<w;j++)列
{
int pixel=((uchar*)src->imageData+i*src->widthStep)[j];
//给时域赋值
TD[j+w*i]=complex<double>(pixel,0);
}
}
//对y方向进行FFT
for (int i=0;i<h;i++)
{
FFT(&TD[w*i],&FD[w*i],wp);
}
保存变换结果
for (int i=0;i<h;i++)
{
for (int j=0;j<w;j++)
{
TD[i+h*j]=FD[j+w*i];
}
}
//对x方向进行FFT
for (int i=0;i<w;i++)
{
FFT(&TD[i*h],&FD[i*h],hp);
}
for (int i=0;i<h;i++)
{
for (int j=0;j<w;j++)
{
计算频谱
double temp=sqrt(FD[j*h+i].real()*FD[j*h+i].real()+
FD[j*h+i].imag()*FD[j*h+i].imag())/100;
if (temp>255)
{
temp=255;判断超过255,直接赋值为255
}
//指向第(i<h/2?i+h/2:i-h/2)行,第j<w/2?j+w/2:j-w/2个像素的指针
//不直接取i和j,是为了将变换后的原点移动到中心
((uchar*)dst->imageData+(i<h/2?i+h/2:i-h/2)*dst->widthStep)[j<w/2?j+w/2:j-w/2]=temp;
}
}
/删除临时变量
delete TD;
delete FD;
return true;

}


计算图像傅立叶变换的过程:首先对每一行做一维FFT,然后对每一列做一维FFT。具体来说,先对第0行的N个点做FFT(实部有值,虚部为0),将FFT输出的实部放回原来第0行的实部,FFT输出的虚部放回第0行的虚部,这样计算完全部行之后,图像的实部和虚部包含的是中间数据,然后用相同的办法进行列方向上的FFT变换,这样N*N的图像经过FFT得到一个N*N的频谱。 

转载请注明出处:http://write.blog.csdn.net/postedit?ref=toolbar&ticket=ST-151395-IMJTd7IBxv5OB7K5dq2y-passport.csdn.net

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值