傅立叶变换是将时域信号分解为不同频率的正弦信号或余弦信号叠加之和(),时域分析只能反映信号的幅值随时间变化的情况,除单频率分量的简谐波外,很难对信息频率的组成及各频率的大小进行详细分析,而信号频谱分析提供了比时域信号波形更直观、更丰富的信息。在实际的图像处理过程中,我们仅仅使用了图像的幅度信息,因为幅度图像包含了我们需要的源图像的几乎所有的几何信息(PS:一般要照射式成像光路在CMOS或者CCD成像设备上得到的主要是幅度信息,如果要得到较多的频率信息,应该采用干涉或者衍射光路)。然而如果想通过修改图像或者相位图像间接修改原空间图像,需要使用逆傅立叶变换来得到修改后的空间图像,这样就必须同时保留幅度图像和相位图像(PS:一幅图像中轮廓属于低频信号,细节属于高频信号)。
二维离散图像M x N的函数f(x,y)的傅立叶变换如下:
正变换:
反变换:
离散傅立叶变换及其反变换总是存在的,每个F(u)由f(x)与对应频率的正弦和余弦乘积组成,(u,v)=(0,0)位置的傅立叶变换值为f(x,y)的均值。对于图像信号而言,空间频率是指单位长度内亮度做周期性变化的次数。图像的频率是表征图像中灰度变化剧烈程度的指标,从傅立叶频率图上可以看到明暗不一的亮点,反映的就是某点与邻域间的差异程度,即图像梯度。
在opencv中,提供了dft函数做傅立叶变换,其函数型如下:
void dft(cv::InputArrar src,cv::OutputArray dst,int flags = 0,int nonzeroRows = 0);
其中参数src表示源图像,dst表示输出图像,flags表示变换类型,nonzeroRows表示前nonzeroRows数据有意义。
但是自带函数不能求解双通道以上的,我自己写了一个傅立叶变换的函数
cv::Mat dftImage(cv::Mat Input)
{
cv::Mat srcImage(Input);
cv::Mat dstImage;
cv::cvtColor(srcImage, srcImage, cv::COLOR_RGB2GRAY);
/******************图像DFT尺寸转换****************************/
const int nRows = srcImage.rows;
const int nCols = srcImage.cols;
int cRows = cv::getOptimalDFTSize(nRows);//图片尺寸转换,获取DFT尺寸
int cCols = cv::getOptimalDFTSize(nCols);
cv::Mat sizeConvMat;
cv::copyMakeBorder(srcImage, sizeConvMat, 0, cRows - nRows, 0, cCols - nCols, cv::BORDER_CONSTANT, cv::Scalar::all(0));
/***********************图像DFT变换*************************/
cv::Mat groupMats[] = { cv::Mat_<float>(sizeConvMat),cv::Mat::zeros(sizeConvMat.size(),CV_32F) };
cv::Mat mergeMat;
cv::merge(groupMats, 2, mergeMat);//通道合并
cv::dft(mergeMat, mergeMat);//DFT变换
cv::split(mergeMat, groupMats);//分离通道
cv::magnitude(groupMats[0], groupMats[1], groupMats[0]);//计算幅度
cv::Mat magnitudeMat = groupMats[0].clone();
magnitudeMat += cv::Scalar::all(1);//归一化操作,赋值加1
cv::log(magnitudeMat, magnitudeMat);//对数变换
cv::normalize(magnitudeMat, magnitudeMat, 0, 1, CV_MINMAX);//归一化
magnitudeMat.convertTo(magnitudeMat, CV_8UC1, 255, 0);//图像类型转换
/*********************频域中心移动*******************/
int cx = magnitudeMat.cols / 2;
int cy = magnitudeMat.rows / 2;
cv::Mat tmp;
cv::Mat q0(magnitudeMat, cv::Rect(0, 0, cx, cy));
cv::Mat q1(magnitudeMat, cv::Rect(cx, 0, cx, cy));
cv::Mat q2(magnitudeMat, cv::Rect(0, cy, cx, cy));
cv::Mat q3(magnitudeMat, cv::Rect(cx, cy, cx, cy));
q0.copyTo(tmp);//交换象限
q3.copyTo(q0);
tmp.copyTo(q3);
q1.copyTo(tmp);
q2.copyTo(q1);
tmp.copyTo(q2);
dstImage = magnitudeMat;
return dstImage;
}