【问题标题】:inverse fourier transform manual merge of real and imaginary傅里叶逆变换手动合并实部和虚部
【发布时间】:2018-05-17 13:03:21
【问题描述】:

我正在为图像的傅立叶变换制作几个包装方法,但遇到了问题。每当我使用标准方法时:

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
}

要提取具体参数,我无法将其重新组合在一起。目前我专注于实数和虚数部分,因为我觉得 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);

//re and 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(&re, &re, &img, true); 在这种情况下,两个窗口中的结果相同(一些随机垃圾但相同)

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

提前感谢您的见解。

【问题讨论】:

    标签: c++ opencv merge fft ifft


    【解决方案1】:

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

     #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;
    }
    

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

    【讨论】:

    • 谢谢,我会处理的。看起来非常好,很有条理。
    • 我将您的代码放在我的 fft 库中并进行测试,我使用了旧的 Lena 图片 ft::ForwardFFT_Mag_Phase(testImg,mag,phi); fft::InverseFFT_Mag_Phase(mag,phi,testImg);没有应用过滤器 - 只是这个序列。加载后测试的图像不同 - 非常模糊。为什么会这样?
    • 我刚刚测试了代码(注释了 2 行:cv::multiply(Mag,mask,Mag); 和 cv::multiply(Phase,mask,Phase);),它得到我是从文件中读取的结果图像(清晰,不模糊)。
    • 我已经在关闭过滤器的情况下回答了更正的代码。另外,我已经更正了缩放问题。
    • 我只是在做 fft::ForwardFFT_Mag_Phase(testImg,mag,phi);垫img; fft::InverseFFT_Mag_Phase(mag,phi,img);输出如下:postimg.org/image/ah24exozh(我的代表不允许我加载图像,所以我不得不即兴发挥,不便之处敬请见谅)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-07-21
    • 2019-07-25
    • 2021-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-10
    相关资源
    最近更新 更多