离散傅立叶变换-----学习记录(7)

#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;
}

你可能感兴趣的:(离散傅立叶变换-----学习记录(7))