傅立叶变换是把图像从空间域转化到频率域的变换。
空间域
一般的情况下,空间域的图像是f(x,y)=灰度级(0-255),形象一点就是一个二维矩阵,每个坐标对应一个颜色值。
频率域
先介绍几个概念
频率:对于图像来说可以指图像颜色值的梯度,即灰度级的变化速度
幅度:可以简单的理解为是频率的权,即该频率所占的比例
能量=幅度(可能不太准确)
变换结果为F(u,v)
F代表幅度值,u代表x方向的频率,v代表y方向的频率
一般会对变换结果进行一定的处理,以便以图片的形式展现,结果就是幅度值被当作灰度级,亮的地方表示能量高
图像的主要部分集中在低频部分,边界和噪声主要集中在高频部分
由于图像变换的结果原点在边缘部分,不容易显示,所以会将原点移动到中心部分。
那么结果便是中间一个亮点朝着周围发散开来,越远离中心位置的能量越低(越暗)。
接下来展示一下代码
#include
#include
using namespace std;
using namespace cv;
int main(int a,char **p)
{
Mat input=imread(p[1],CV_LOAD_IMAGE_GRAYSCALE);//以灰度图像的方式读入图片
//如果不知到怎么传入p[1]。可以改为
//Mat input=imread("image.jpg",CV_LOAD_IMAGE_GRAYSCALE);
imshow("input",input);//显示原图
int w=getOptimalDFTSize(input.cols);
int h=getOptimalDFTSize(input.rows);//获取最佳尺寸,快速傅立叶变换要求尺寸为2的n次方
Mat padded;
copyMakeBorder(input,padded,0,h-input.rows,0,w-input.cols,BORDER_CONSTANT,Scalar::all(0));//填充图像保存到padded中
Mat plane[]={Mat_(padded),Mat::zeros(padded.size(),CV_32F)};//创建通道
Mat complexIm;
merge(plane,2,complexIm);//合并通道
dft(complexIm,complexIm);//进行傅立叶变换,结果保存在自身
split(complexIm,plane);//分离通道
magnitude(plane[0],plane[1],plane[0]);//获取幅度图像,0通道为实数通道,1为虚数,因为二维傅立叶变换结果是复数
int cx=padded.cols/2;int cy=padded.rows/2;//一下的操作是移动图像,左上与右下交换位置,右上与左下交换位置
Mat temp;
Mat part1(plane[0],Rect(0,0,cx,cy));
Mat part2(plane[0],Rect(cx,0,cx,cy));
Mat part3(plane[0],Rect(0,cy,cx,cy));
Mat part4(plane[0],Rect(cx,cy,cx,cy));
part1.copyTo(temp);
part4.copyTo(part1);
temp.copyTo(part4);
part2.copyTo(temp);
part3.copyTo(part2);
temp.copyTo(part3);
//*******************************************************************
//Mat _complexim(complexIm,Rect(padded.cols/4,padded.rows/4,padded.cols/2,padded.rows/2));
//opyMakeBorder(_complexim,_complexim,padded.rows/4,padded.rows/4,padded.cols/4,padded.cols/4,BORDER_CONSTANT,Scalar::all(0.75));
Mat _complexim;
complexIm.copyTo(_complexim);//把变换结果复制一份,进行逆变换,也就是恢复原图
Mat iDft[]={Mat::zeros(plane[0].size(),CV_32F),Mat::zeros(plane[0].size(),CV_32F)};//创建两个通道,类型为float,大小为填充后的尺寸
idft(_complexim,_complexim);//傅立叶逆变换
split(_complexim,iDft);//结果貌似也是复数
magnitude(iDft[0],iDft[1],iDft[0]);//分离通道,主要获取0通道
normalize(iDft[0],iDft[0],1,0,CV_MINMAX);//归一化处理,float类型的显示范围为0-1,大于1为白色,小于0为黑色
imshow("idft",iDft[0]);//显示逆变换
//*******************************************************************
plane[0]+=Scalar::all(1);//傅立叶变换后的图片不好分析,进行对数处理,结果比较好看
log(plane[0],plane[0]);
normalize(plane[0],plane[0],1,0,CV_MINMAX);
imshow("dft",plane[0]);
waitKey(100086110);
return 0;
}
运行结果
接下来介绍一下运行结果
左边到右边,第一副图像是原图,第二图是幅值图,第三副图是逆变换后的结果
幅值图,结果和预料的一样
逆变换的结果显示,多了一圈黑边,这是因为填充后的结果