OpenCV 频域-时域的傅里叶变换及逆变换 C++

在这边文章中已完成了正向变换,使用idft()实现逆变换;

大致流程如下:

1、读取图像,获取最佳尺寸,快速傅里叶变换要求为2的N次方
2、以0为边缘填充图像;
3、为原图像增加一个通道,进行傅里叶变换;
4、分离通道,获取幅度图像,交叉替换 四分之一区域;
5、copy一份用于逆变换,idft-->分离channel,归一化;
6、log处理dft变换后的图像,方便查看;
 

代码如下:

#include<opencv2/opencv.hpp>
#include<iostream>

using namespace std;
using namespace cv;

static void help(char* progName)
{
    cout << endl
        <<  "This program demonstrated the use of the discrete Fourier transform (DFT). " << endl
        <<  "The dft of an image is taken and it's power spectrum is displayed."          << endl
        <<  "Usage:"                                                                      << endl
        << progName << " [image_name -- default ../data/lena.jpg] "               << endl << endl;
}

int main(int argc,char *argv[])
{
    help(argv[0]);

    const char* filename = argc >=2 ? argv[1] : "../data/lena.jpg";

    Mat input = imread(filename, IMREAD_GRAYSCALE);
    if( input.empty())
        return -1;
    imshow("input",input);//显示原图

    int w=getOptimalDFTSize(input.cols);
    int h=getOptimalDFTSize(input.rows);//获取最佳尺寸,快速傅立叶变换要求尺寸为2的n次方
    Mat padded;     //将输入图像延扩到最佳的尺寸  在边缘添加0
    copyMakeBorder(input,padded,0,h-input.rows,0,w-input.cols,BORDER_CONSTANT,Scalar::all(0));//填充图像保存到padded中
    Mat plane[]={Mat_<float>(padded),Mat::zeros(padded.size(),CV_32F)};//创建通道
    Mat complexIm;
    merge(plane,2,complexIm);//为延扩后的图像增添一个初始化为0的通道
    dft(complexIm,complexIm);//进行傅立叶变换,结果保存在自身
    split(complexIm,plane);//分离通道
    magnitude(plane[0],plane[1],plane[0]);//获取幅度图像,0通道为实数通道,1为虚数,因为二维傅立叶变换结果是复数
    plane[0] = plane[0](Rect(0, 0, plane[0].cols & -2, plane[0].rows & -2));
    int cx=padded.cols/2;int cy=padded.rows/2;//一下的操作是移动图像,左上与右下交换位置,右上与左下交换位置
    Mat temp;
    Mat part1(plane[0],Rect(0,0,cx,cy));
    Mat part2(plane[0],Rect(cx,0,cx,cy));
    Mat part3(plane[0],Rect(0,cy,cx,cy));
    Mat part4(plane[0],Rect(cx,cy,cx,cy));


    part1.copyTo(temp);
    part4.copyTo(part1);
    temp.copyTo(part4);

    part2.copyTo(temp);
    part3.copyTo(part2);
    temp.copyTo(part3);
//*******************************************************************

    Mat _complexim;
    complexIm.copyTo(_complexim);//把变换结果复制一份,进行逆变换,也就是恢复原图
    Mat iDft[]={Mat::zeros(plane[0].size(),CV_32F),Mat::zeros(plane[0].size(),CV_32F)};//创建两个通道,类型为float,大小为填充后的尺寸
    idft(_complexim,_complexim);//傅立叶逆变换
    split(_complexim,iDft);//结果貌似也是复数
    magnitude(iDft[0],iDft[1],iDft[0]);//分离通道,主要获取0通道
//    normalize(iDft[0],iDft[0],1,0,CV_MINMAX);//归一化处理,float类型的显示范围为0-1,大于1为白色,小于0为黑色
    normalize(iDft[0], iDft[0], 0, 1, NORM_MINMAX);
    imshow("idft",iDft[0]);//显示逆变换
//*******************************************************************
    // compute the magnitude and switch to logarithmic scale
    // => log(1 + sqrt(Re(DFT(I))^2 + Im(DFT(I))^2))
    plane[0]+=Scalar::all(1);//傅立叶变换后的图片不好分析,进行对数处理,结果比较好看
    log(plane[0],plane[0]);
    normalize(plane[0],plane[0],0,1,NORM_MINMAX);

    imshow("dft",plane[0]);
    waitKey();
    return 0;
}

结果显示:

原图:

dft图:

idft图像:

逆变换的结果显示,多了一圈黑边,这是因为填充后的结果

猜你喜欢

转载自blog.csdn.net/cyf15238622067/article/details/87917766