简单来说,对一张图像使用傅里叶变换就是将它分解成正弦和余弦两部分,也就是将图像从空间域转换到频域。在频域里,高频部分代表了图像的细节、纹理信息,而低频部分代表了图像的轮廓信息。
傅里叶变换在图像处理中的应用:图像的增强与图像去噪、图像分割之边缘检测、图像特征提取、图像压缩等。
关于傅里叶变换的帖子:https://zhuanlan.zhihu.com/p/19763358?columnSlug=wille 能很好的帮助理解傅里叶变换。
下面举一个opencv里面的实例:
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
int main(int argc,char** argv)
{
const char* filename = argc >= 2 ? argv[1] : "active-1807533_960_720.jpg";
Mat J,I;
J = imread(filename,CV_LOAD_IMAGE_COLOR);//读入图像
cvtColor(J,I,CV_BGR2GRAY);
int m = getOptimalDFTSize(I.rows); //为了计算速度考虑,图像尺寸为2^n时计算最快,其次是如果是2,3,5的倍数的话也能更有效率的傅里叶转换。
int n = getOptimalDFTSize(I.cols); //cvGetOptimalDFTSize是寻找最接近的一个符合2^n次方的数,或者可以分解为2,3,5的数。
Mat padded;
copyMakeBorder(I,padded,0,m - I.rows,0,n-I.cols,BORDER_CONSTANT,Scalar::all(0));//扩展一个图像的边界
//第一个参数:输入图像
//第二个参数:输出图像
//第3-6个参数:分别表示在源图像的上下左右四个方向上扩充多少个像素
//第七个参数:边界类型,常取值为BORDER_CONSTANT
//第八个参数:扩充部分的像素值
Mat planes[] = {Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F)};//新建一个Mat类型的数组,第一个元素存放扩展边界后的图像,第二个元素初始化为零。
Mat complexI;
merge(planes,2,complexI);//该函数是把多个单通道数组连接成1个多通道数组,这里把planes的两个元素合成一个2通道的图像。
dft(complexI,complexI);//dft()的主要作用是对一维或二维浮点数组进行傅里叶变换或反变换。
Mat magI;
split(complexI,planes);//split()函数,把1个多通道函数分解成多个单通道函数。
magnitude(planes[0],planes[1],magI);//该函数是计算输入矩阵x和y对应该的每个像素平方求和后开根号保存在输出矩阵magnitude中。
magI += Scalar::all(1);//见图1
log(magI,magI);
magI = magI(Rect(0, 0, magI.cols & -2, magI.rows & -2));
int cx = magI.cols/2;
int cy = magI.rows/2;
Mat q0(magI, Rect(0, 0, cx, cy)); // Top-Left - Create a ROI per quadrant
Mat q1(magI, Rect(cx, 0, cx, cy)); // Top-Right
Mat q2(magI, Rect(0, cy, cx, cy)); // Bottom-Left
Mat q3(magI, Rect(cx, cy, cx, cy)); // Bottom-Right
Mat tmp; // swap quadrants (Top-Left with Bottom-Right)
q0.copyTo(tmp);
q3.copyTo(q0);
tmp.copyTo(q3);
q1.copyTo(tmp); // swap quadrant (Top-Right with Bottom-Left)
q2.copyTo(q1);
tmp.copyTo(q2);
normalize(magI, magI, 0, 1, CV_MINMAX); // Transform the matrix with float values into a
// viewable image form (float between values 0 and 1).
imshow("原图",J);
imshow("padded",padded);
imshow("planes[0]",planes[0]);
imshow("planes[1]",planes[1]);
imshow("magI",magI);
waitKey(0);
return 0;
}
原始图像:
灰度+边界:
频域实部:
频域虚部:
频域图像: