#include "opencv2/highgui/highgui.hpp" #include "opencv2/core/core.hpp" #include "opencv2/imgproc/imgproc.hpp" #include "iostream" using namespace cv; int main(int argc, char* argv[]) { const char* filename = argc >= 2 ? argv[1] : "lena.jpg"; Mat I = imread( filename, CV_LOAD_IMAGE_GRAYSCALE ); //Mat I = imread( "lena.jpg", CV_LOAD_IMAGE_GRAYSCALE ); if ( I.empty()) return -1; Mat padded; //将输入图像延扩到最佳的尺寸 int m = getOptimalDFTSize( I.rows ); int n = getOptimalDFTSize( I.cols ); copyMakeBorder( I, padded, 0, m - I.rows, 0, n - I.cols, BORDER_CONSTANT, Scalar::all(0) ); //扩展部分填充0值 Mat planes[] = { Mat_<float>(padded), Mat::zeros( padded.size(), CV_32F ) }; //为存储复数部分开辟一个0的通道,因为每幅图像变换后有两个值 Mat complexI; merge( planes, 2, complexI ); //个人理解是将数组中的两个Mat进行合并成为一个Mat dft( complexI, complexI ); //进行DFT变换,变换后还是存回原来的地方 split( complexI, planes ); //将变化后的值进行拆分,plane[0]存着实部参数,plane[1]存着虚部参数 magnitude( planes[0], planes[1], planes[0] ); //进行求模值运算 Mat magI = planes[0]; magI += Scalar::all(1); //进行一个对数转换工作log(1+M) log( magI, magI ); //傅立叶变换的幅度值范围大到不适合在屏幕上显示 // 截取频谱,每个奇数行或者列 magI = magI(Rect(0, 0, magI.cols & -2, magI.rows & -2)); // 重新排列傅里叶图,使得原图像的(0,0)点能够在图像中心处 int cx = magI.cols/2; int cy = magI.rows/2; Mat q0(magI, Rect(0, 0, cx, cy)); // 左上,Rect中参数为左上角的坐标,长和宽 Mat q1(magI, Rect(cx, 0, cx, cy)); // 右上 Mat q2(magI, Rect(0, cy, cx, cy)); // 左下 Mat q3(magI, Rect(cx, cy, cx, cy)); // 右下 Mat tmp; // 左上和右下交换 q0.copyTo(tmp); q3.copyTo(q0); tmp.copyTo(q3); //不明白为什么要交换,上面这个交换确实可以将原图像(0,0)坐标弄到图像中心点,下面再交换依次干嘛?就是将四个直角弄到中心处了 q1.copyTo(tmp); // 右上和左下交换 q2.copyTo(q1); tmp.copyTo(q2); normalize(magI, magI, 0, 1, CV_MINMAX); // 归一化处理 imshow("Input Image", I ); // 输入的图像 imshow("spectrum magnitude", magI); //频谱图 waitKey(); return 0; }