傅立叶变换是把图像从空间域转化到频率域的变换。
空间域
一般的情况下,空间域的图像是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_<
float>(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;
-
}
运行结果
接下来介绍一下运行结果
左边到右边,第一副图像是原图,第二图是幅值图,第三副图是逆变换后的结果
幅值图,结果和预料的一样
逆变换的结果显示,多了一圈黑边,这是因为填充后的结果