逆傅里叶变换手动合并实部和虚部

时间:2013-11-19 15:02:29

标签: c++ opencv merge fft ifft

我正在为图像的傅里叶变换制作一些包装方法并遇到了问题。每当我使用标准方法时:

void fft::dfft(Mat* img,Mat* result){
    Mat image;
    img->convertTo(image, CV_32F);
    cv::dft(image, *result, cv::DFT_SCALE|cv::DFT_COMPLEX_OUTPUT);
}

反转操作:

void fft::idft(Mat* fourier, Mat* img) {
    //invert:
    Mat inverseTransform;
    dft(*fourier, inverseTransform, cv::DFT_INVERSE|cv::DFT_REAL_OUTPUT);
    //restore image to 8 bits (fourier needs to use float at least
    Mat res;
    inverseTransform.convertTo(res, CV_8U);
    res.copyTo(*img);
}
一切都好。但是,当我尝试使用这对时:

void fft::dfft(Mat* img, Mat* mag, Mat* phi, Mat* re, Mat* im) {

/*SPECAL NOTE: dft is faster for images with size being multiple of two three and five. An OCV fmethod getOptrimalDFTSize comes in handy*/
Mat paddedImg; //expand input image to the optimal size
int m = getOptimalDFTSize(img->rows);
int n = getOptimalDFTSize(img->cols);
copyMakeBorder(*img, paddedImg, 0, m - img->rows, 0, n-img->cols, BORDER_CONSTANT, Scalar::all(0));

/*prepare space to store the image*/
Mat planes[] = {Mat_<float>(paddedImg), Mat::zeros(paddedImg.size(), CV_32F)};
Mat complexImg;
merge(planes, 2, complexImg);

/*Actual dft:*/
dft(complexImg, complexImg);

/*Get magnitude:*/
split(complexImg, planes);
Mat magImg, phasImg;
planes[0].copyTo(*re);
planes[1].copyTo(*im);

cout << "intern Real = "<< planes[0] << endl;

magnitude(planes[0], planes[1], magImg); //magnitude will be stored in planes[0]
phase(planes[0], planes[1], phasImg);


magImg.copyTo(*mag);
phasImg.copyTo(*phi);
#ifdef debug
namedWindow("Input Image", 0 );
imshow("Input Image", *img);
namedWindow( "Image magnitude", 0 );
imshow("Image magnitude", magImg);
waitKey(0);
#endif
}

要提取具体参数,我不能把它重新组合在一起。目前我专注于Real和Imaginary部分,因为我觉得Mag / Phi将以相同的方式工作,只是首先从Mag / Phi转换回真实和虚构。

void fft::idft(Mat* re, Mat* im, Mat* img, bool dummy) {
Mat inverseTransform;

Mat fourier(re->rows, re->cols, CV_32FC2);
vector<Mat> planes;
planes.push_back(*re);
planes.push_back(*im);

//重新正确进入内部(已验证)

Mat padded;
Mat complex;
Mat pp[] = {Mat_<float>(*re), Mat::zeros(re->size(), CV_32F)};
pp[0] = *re;
pp[1] = *im;
merge(pp, 2, complex);         // Add to the expanded another plane with zeros

cv::merge(planes, fourier);

dft(complex, inverseTransform, cv::DFT_INVERSE|cv::DFT_REAL_OUTPUT);

Mat res;
inverseTransform.convertTo(res, CV_8U);
cv::imshow("iFFT1", res);
dft(fourier, inverseTransform, cv::DFT_INVERSE|cv::DFT_REAL_OUTPUT);
inverseTransform.convertTo(res, CV_8U);
cv::imshow("iFFT2", res);


res.copyTo(*img);
}

两种方法(使用矢量和数组pp)产生相同的白色矩形。看看它是否做了我通过的任何事情 fft :: idft(&amp; re,&amp; re,&amp; img,true); 在这种情况下,两个窗口的结果是相同的(一些随机垃圾但相同)

我怀疑问题在于错误的合并程序,但我没有其他想法如何恢复原始表格?

提前感谢您的见解。

1 个答案:

答案 0 :(得分:2)

这是我的傅立叶域过滤器,我认为它应该是有用的:

enter image description here

 #pragma once
#include <string>
#include <iostream>
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;
//----------------------------------------------------------
// Recombinate quadrants
//----------------------------------------------------------
void Recomb(Mat &src,Mat &dst)
{
    int cx = src.cols>>1;
    int cy = src.rows>>1;
    Mat tmp;
    tmp.create(src.size(),src.type());
    src(Rect(0, 0, cx, cy)).copyTo(tmp(Rect(cx, cy, cx, cy)));
    src(Rect(cx, cy, cx, cy)).copyTo(tmp(Rect(0, 0, cx, cy)));  
    src(Rect(cx, 0, cx, cy)).copyTo(tmp(Rect(0, cy, cx, cy)));
    src(Rect(0, cy, cx, cy)).copyTo(tmp(Rect(cx, 0, cx, cy)));
    dst=tmp;
}
//----------------------------------------------------------
// Forward fft
//----------------------------------------------------------
void ForwardFFT(Mat &Src, Mat *FImg)
{
    int M = getOptimalDFTSize( Src.rows );
    int N = getOptimalDFTSize( Src.cols );
    Mat padded;    
    copyMakeBorder(Src, padded, 0, M - Src.rows, 0, N - Src.cols, BORDER_CONSTANT, Scalar::all(0));
    // Create complex image
    // planes[0] image , planes[1] filled by zeroes
    Mat planes[2] = {Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F)};
    Mat complexImg;
    merge(planes, 2, complexImg); 
    dft(complexImg, complexImg,DFT_SCALE);    
    // After tranform we also get complex image 
    split(complexImg, planes);

    // 
    planes[0] = planes[0](Rect(0, 0, planes[0].cols & -2, planes[0].rows & -2));
    planes[1] = planes[1](Rect(0, 0, planes[1].cols & -2, planes[1].rows & -2));

    Recomb(planes[0],planes[0]);
    Recomb(planes[1],planes[1]);

    FImg[0]=planes[0].clone();
    FImg[1]=planes[1].clone();
}
//----------------------------------------------------------
// Inverse FFT
//----------------------------------------------------------
void InverseFFT(Mat *FImg,Mat &Dst)
{
    Recomb(FImg[0],FImg[0]);
    Recomb(FImg[1],FImg[1]);
    Mat complexImg;
    merge(FImg, 2, complexImg);
    // Inverse transform
    dft(complexImg, complexImg,  DFT_INVERSE);
    split(complexImg, FImg);        
    FImg[0].copyTo(Dst);
}
//----------------------------------------------------------
// Forward FFT using Magnitude and phase
//----------------------------------------------------------
void ForwardFFT_Mag_Phase(Mat &src, Mat &Mag,Mat &Phase)
{
    Mat planes[2];
    ForwardFFT(src,planes);
    Mag.zeros(planes[0].rows,planes[0].cols,CV_32F);
    Phase.zeros(planes[0].rows,planes[0].cols,CV_32F);
    cv::cartToPolar(planes[0],planes[1],Mag,Phase);
}
//----------------------------------------------------------
// Inverse FFT using Magnitude and phase
//----------------------------------------------------------
void InverseFFT_Mag_Phase(Mat &Mag,Mat &Phase, Mat &dst)
{
    Mat planes[2];
    planes[0].create(Mag.rows,Mag.cols,CV_32F);
    planes[1].create(Mag.rows,Mag.cols,CV_32F);
    cv::polarToCart(Mag,Phase,planes[0],planes[1]);
    InverseFFT(planes,dst);
}
//----------------------------------------------------------
// MAIN
//----------------------------------------------------------
int main(int argc, char* argv[])
{
    // src image
    Mat img;
    // Magnitude
    Mat Mag;
    // Phase
    Mat Phase;
    // Image loading
    img=imread("d:\\ImagesForTest\\lena.jpg",0);
    resize(img,img,Size(512,512));
    // Image size
    cout<<img.size().width<<endl;
    cout<<img.size().height<<endl;

    // 
    ForwardFFT_Mag_Phase(img,Mag,Phase);    

    //----------------------------------------------------------
    // Filter
    //----------------------------------------------------------
    // draw ring    
    int R=100;  // External radius
    int r=30;   // internal radius
    Mat mask;
    mask.create(Mag.cols,Mag.rows,CV_32F);
    int cx = Mag.cols>>1;
    int cy = Mag.rows>>1;       
    mask=1;
    cv::circle(mask,cv::Point(cx,cy),R,CV_RGB(0,0,0),-1);   
    cv::circle(mask,cv::Point(cx,cy),r,CV_RGB(1,1,1),-1);
    //mask=1-mask; // uncomment for inversion

    //cv::multiply(Mag,mask,Mag); // uncomment to turn filter on
    //cv::multiply(Phase,mask,Phase);
    //----------------------------------------------------------
    // Inverse transform
    //----------------------------------------------------------
    InverseFFT_Mag_Phase(Mag,Phase,img);    

    //----------------------------------------------------------
    // Results output
    //----------------------------------------------------------
    // 
    Mat LogMag;
    LogMag.zeros(Mag.rows,Mag.cols,CV_32F);
    LogMag=(Mag+1);
    cv::log(LogMag,LogMag);
    //---------------------------------------------------
    imshow("Magnitude Log", LogMag);
    imshow("Phase", Phase);
    // img - now in CV_32FC1 format,we need CV_8UC1 or scale it by factor 1.0/255.0  
    img.convertTo(img,CV_8UC1);
    imshow("Filtering result", img);    
    //----------------------------------------------------------
    // Wait key press
    //----------------------------------------------------------
    waitKey(0);
    return 0;
    }

抱歉,我无法重现您的结果我已经测试了代码并且工作正常:

#pragma once
#include <string>
#include <iostream>
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;
//----------------------------------------------------------
// Recombinate quadrants
//----------------------------------------------------------
void Recomb(Mat &src,Mat &dst)
{
    int cx = src.cols>>1;
    int cy = src.rows>>1;
    Mat tmp;
    tmp.create(src.size(),src.type());
    src(Rect(0, 0, cx, cy)).copyTo(tmp(Rect(cx, cy, cx, cy)));
    src(Rect(cx, cy, cx, cy)).copyTo(tmp(Rect(0, 0, cx, cy)));  
    src(Rect(cx, 0, cx, cy)).copyTo(tmp(Rect(0, cy, cx, cy)));
    src(Rect(0, cy, cx, cy)).copyTo(tmp(Rect(cx, 0, cx, cy)));
    dst=tmp;
}
//----------------------------------------------------------
// Forward fft
//----------------------------------------------------------
void ForwardFFT(Mat &Src, Mat *FImg)
{
    int M = getOptimalDFTSize( Src.rows );
    int N = getOptimalDFTSize( Src.cols );
    Mat padded;    
    copyMakeBorder(Src, padded, 0, M - Src.rows, 0, N - Src.cols, BORDER_CONSTANT, Scalar::all(0));
    // Create complex image
    // planes[0] image , planes[1] filled by zeroes
    Mat planes[2] = {Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F)};
    Mat complexImg;
    merge(planes, 2, complexImg); 
    dft(complexImg, complexImg,DFT_SCALE);    
    // After tranform we also get complex image 
    split(complexImg, planes);

    // 
    planes[0] = planes[0](Rect(0, 0, planes[0].cols & -2, planes[0].rows & -2));
    planes[1] = planes[1](Rect(0, 0, planes[1].cols & -2, planes[1].rows & -2));

    Recomb(planes[0],planes[0]);
    Recomb(planes[1],planes[1]);

    FImg[0]=planes[0].clone();
    FImg[1]=planes[1].clone();
}
//----------------------------------------------------------
// Inverse FFT
//----------------------------------------------------------
void InverseFFT(Mat *FImg,Mat &Dst)
{
    Recomb(FImg[0],FImg[0]);
    Recomb(FImg[1],FImg[1]);
    Mat complexImg;
    merge(FImg, 2, complexImg);
    // Inverse transform
    dft(complexImg, complexImg,  DFT_INVERSE);
    split(complexImg, FImg);        
    FImg[0].copyTo(Dst);
}
//----------------------------------------------------------
// Forward FFT using Magnitude and phase
//----------------------------------------------------------
void ForwardFFT_Mag_Phase(Mat &src, Mat &Mag,Mat &Phase)
{
    Mat planes[2];
    ForwardFFT(src,planes);
    Mag.zeros(planes[0].rows,planes[0].cols,CV_32F);
    Phase.zeros(planes[0].rows,planes[0].cols,CV_32F);
    cv::cartToPolar(planes[0],planes[1],Mag,Phase);
}
//----------------------------------------------------------
// Inverse FFT using Magnitude and phase
//----------------------------------------------------------
void InverseFFT_Mag_Phase(Mat &Mag,Mat &Phase, Mat &dst)
{
    Mat planes[2];
    planes[0].create(Mag.rows,Mag.cols,CV_32F);
    planes[1].create(Mag.rows,Mag.cols,CV_32F);
    cv::polarToCart(Mag,Phase,planes[0],planes[1]);
    InverseFFT(planes,dst);
}
//----------------------------------------------------------
// MAIN
//----------------------------------------------------------
int main(int argc, char* argv[])
{
    // src image
    Mat img;
    // Magnitude
    Mat Mag;
    // Phase
    Mat Phase;
    // Image loading (grayscale)
    img=imread("d:\\ImagesForTest\\lena.jpg",0);
    ForwardFFT_Mag_Phase(img,Mag,Phase);    
    //----------------------------------------------------------
    // Inverse transform
    //----------------------------------------------------------
    InverseFFT_Mag_Phase(Mag,Phase,img);    
    img.convertTo(img,CV_8UC1);
    imshow("Filtering result", img);    
    //----------------------------------------------------------
    // Wait key press
    //----------------------------------------------------------
    waitKey(0);
    return 0;
}

它获得与输入相同的图像。