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圖像:

逆變換的結果顯示,多了一圈黑邊,這是因爲填充後的結果

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章