#include<opencv2\core\core.hpp>
#include<opencv2\imgcodecs\imgcodecs.hpp>
#include<opencv2\highgui\highgui.hpp>
#include<opencv2\opencv.hpp> //包含cvtColor()
#include<iostream>
using namespace std;
using namespace cv;
int main()
{
//1.读入图片
Mat srcImage = imread("LOL_pa4.jpg");
if (!srcImage.data) { cout << "读入图片存在错误,当前目录下是否存在此图片 ! " << endl; }
//2.将图片延扩到最佳的尺寸,边界用0补充
int m = getOptimalDFTSize(srcImage.rows);
int n = getOptimalDFTSize(srcImage.cols);
Mat padded;
copyMakeBorder(srcImage, padded, 0, m - srcImage.rows, 0, n - srcImage.cols, BORDER_CONSTANT, Scalar::all(0));
//3.为傅里叶变换的结果(实部和虚部)分配储存空间
//将planes数组组合成一个多通道的数组complexI
cvtColor(padded, padded, COLOR_RGB2GRAY);
Mat planes[] = {Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F)};
Mat complexI(padded.size(), CV_32F);
merge(planes,2,complexI);
//4.就地进行离散傅里叶变换
dft(complexI, complexI);
//5.将复数转换为幅值,即=>log(1+M)(进行对数尺寸缩放) : M=sqrt(Re(DFT)^2+Im(DFT)^2)
split(complexI, planes); //planes[0]=Re(DFT(I)),planes[1]=Im(DFT(I))
magnitude(planes[0], planes[1], planes[0]);
Mat magnitudeImage = planes[0];
//6.进行对数尺寸的缩放
magnitudeImage += Scalar::all(1);
log(magnitudeImage, magnitudeImage);
//7.剪切和重分布幅度图象限,若有奇数行或奇数列。进行频谱剪裁
magnitudeImage = magnitudeImage(Rect(0, 0, magnitudeImage.cols& -2, magnitudeImage.rows& -2));
//重新排列傅里叶图像中的象限,使得远点位于图像中心
int cx = magnitudeImage.cols / 2;
int cy = magnitudeImage.rows / 2;
Mat q0(magnitudeImage, Rect(0, 0, cx, cy)); //图片左上
Mat q1(magnitudeImage, Rect(cx, 0, cx, cy)); //图片右上
Mat q2(magnitudeImage, Rect(0, cy, cx, cy)); //图片左下
Mat q3(magnitudeImage, Rect(cx, cy, cx, cy)); //图片右下
//交换象限(左上与右下)
Mat temp;
q0.copyTo(temp); //temp=q0;
q3.copyTo(q0); //q0=q3;
temp.copyTo(q3); //q3=temp;
//交换象限(右上与左下)
q1.copyTo(temp); //temp=q1
q2.copyTo(q1); //q1=q2
temp.copyTo(q2); //q2=temp
//8.归一化
normalize(magnitudeImage, magnitudeImage, 0, 1, NORM_MINMAX);
//9.显示效果图
//imshow("padded", padded);
//imshow("原始图像", srcImage);
imshow("频谱幅值", magnitudeImage);
waitKey(0);
return 0;
} |