#include
#include
#include
void fft2shift(IplImage *src, IplImage *dst)
{
IplImage *image_Re = 0, *image_Im = 0;
int nRow, nCol, i, j, cy, cx;
double scale, shift, tmp13, tmp24;
image_Re = cvCreateImage(cvGetSize(src), IPL_DEPTH_64F, 1);
//Imaginary part
image_Im = cvCreateImage(cvGetSize(src), IPL_DEPTH_64F, 1);
cvSplit( src, image_Re, image_Im, 0, 0 );
//具体原理见冈萨雷斯数字图像处理p123
// Compute the magnitude of the spectrum Mag = sqrt(Re^2 + Im^2)
//计算傅里叶谱
cvPow( image_Re, image_Re, 2.0);
cvPow( image_Im, image_Im, 2.0);
cvAdd( image_Re, image_Im, image_Re);
cvPow( image_Re, image_Re, 0.5 );
//对数变换以增强灰度级细节(这种变换使以窄带低灰度输入图像值映射
//一宽带输出值,具体可见冈萨雷斯数字图像处理p62)
// Compute log(1 + Mag);
cvAddS( image_Re, cvScalar(1.0), image_Re ); // 1 + Mag
cvLog( image_Re, image_Re ); // log(1 + Mag)
//Rearrange the quadrants of Fourier image so that the origin is at the image center
nRow = src->height;
nCol = src->width;
cy = nRow/2; // image center
cx = nCol/2;
//CV_IMAGE_ELEM为OpenCV定义的宏,用来读取图像的像素值,这一部分就是进行中心变换
for( j = 0; j < cy; j++ ){
for( i = 0; i < cx; i++ ){
//中心化,将整体份成四块进行对角交换
tmp13 = CV_IMAGE_ELEM( image_Re, double, j, i);
CV_IMAGE_ELEM( image_Re, double, j, i) = CV_IMAGE_ELEM(
image_Re, double, j+cy, i+cx);
CV_IMAGE_ELEM( image_Re, double, j+cy, i+cx) = tmp13;
tmp24 = CV_IMAGE_ELEM( image_Re, double, j, i+cx);
CV_IMAGE_ELEM( image_Re, double, j, i+cx) =
CV_IMAGE_ELEM( image_Re, double, j+cy, i);
CV_IMAGE_ELEM( image_Re, double, j+cy, i) = tmp24;
}
}
//归一化处理将矩阵的元素值归一为[0,255]
//[(f(x,y)-minVal)/(maxVal-minVal)]*255
double minVal = 0, maxVal = 0;
// Localize minimum and maximum values
cvMinMaxLoc( image_Re, &minVal, &maxVal );
// Normalize image (0 - 255) to be observed as an u8 image
scale = 255/(maxVal - minVal);
shift = -minVal * scale;
cvConvertScale(image_Re, dst, scale, shift);
cvReleaseImage(&image_Re);
cvReleaseImage(&image_Im);
}
int main(int argc, char* argv[])
{
IplImage *src ,*dst,*Invdst,*temp,*Im = 0,*Re,*FourierImage;
temp = cvLoadImage("C:\\Users\\Lonely\\Desktop\\lena.jpg",0);
//显示原图像
cvNamedWindow("待变换图像",0);
cvShowImage("待变换图像",temp);
dst = cvCreateImage(cvGetSize(temp),temp->depth,1);
FourierImage = cvCreateImage(cvGetSize(temp),temp->depth,1);
Invdst = cvCreateImage(cvGetSize(temp),temp->depth,1);
src = cvCreateImage(cvGetSize(temp),IPL_DEPTH_64F,2);
Im = cvCreateImage(cvGetSize(temp),IPL_DEPTH_64F,1);
Re = cvCreateImage(cvGetSize(temp),IPL_DEPTH_64F,1);
//利用cvConcertScale转换数据类型
cvConvertScale(temp,Re);
//复数通道的灰度值设为0
cvZero(Im);
//傅里叶变换在复数域,在opencv中表示为二通道
cvMerge(Re,Im,NULL,NULL,src);
IplImage *Fourier = cvCreateImage(cvGetSize(temp),IPL_DEPTH_64F,2);
IplImage *InvFourier = cvCreateImage(cvGetSize(temp),IPL_DEPTH_64F,2);
//傅里叶变换
cvDFT(src,Fourier,CV_DXT_FORWARD);
cvDFT(Fourier,InvFourier,CV_DXT_INV_SCALE);
cvSplit(Fourier,Re,Im,NULL,NULL);
//利用cvConcertScale转换数据类型
cvConvertScale(Re,dst);
//显示傅里叶变换图像
cvNamedWindow("傅里叶变换图像",0);
cvShowImage("傅里叶变换图像",dst);
//中心化
fft2shift(Fourier,FourierImage);
cvNamedWindow("中心化傅里叶变换图像",0);
cvShowImage("中心化傅里叶变换图像",FourierImage);
cvSplit(InvFourier,Re,Im,NULL,NULL);
//利用cvConcertScale转换数据类型
cvConvertScale(Re,Invdst);
//显示傅里叶逆变换图像
cvNamedWindow("傅里叶逆变换图像",0);
cvShowImage("傅里叶逆变换图像",Invdst);
cvWaitKey(0);
//释放内存
cvReleaseImage(&src);
cvReleaseImage(&dst);
cvReleaseImage(&Invdst);
cvReleaseImage(&temp);
cvReleaseImage(&Im);
cvReleaseImage(&Re);
cvReleaseImage(&Fourier);
cvReleaseImage(&InvFourier);
cvDestroyAllWindows();
}
fft2shift来自http://blog.csdn.net/abcjennifer/article/details/7359952
OpenCV版本:2.4.4