在OpenCV 2.4.8中使用cvDFT和DFT的结果不同

时间:2014-02-24 10:02:57

标签: c++ opencv dft

我在OpenCV 2.4.8 for c ++中遇到DFT功能问题。

我使用10相正弦曲线的图像来比较旧的cvDFT()和较新的c ++函数DFT()(一维DFT行)。

旧版本给出了逻辑结果:像素0和10处的峰值非常高,其余几乎为0。

新版本给出了奇怪的结果,其中包括各种峰值。

这是我的代码:

#include "stdafx.h"

#include <opencv2\core\core_c.h>
#include <opencv2\core\core.hpp>
#include <opencv2\imgproc\imgproc_c.h>
#include <opencv2\imgproc\imgproc.hpp>
#include <opencv2\highgui\highgui_c.h>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\legacy\compat.hpp>

using namespace cv;


void OldMakeDFT(Mat original, double* result)
{ 
    const int width = original.cols;
    const int height = 1;

    IplImage* fftBlock = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);

    IplImage* imgReal = cvCreateImage(cvSize(width, height), IPL_DEPTH_32F, 1);
    IplImage* imgImag = cvCreateImage(cvSize(width, height), IPL_DEPTH_32F, 1);
    IplImage* imgDFT = cvCreateImage(cvSize(width, height), IPL_DEPTH_32F, 2);

    Rect roi(0, 0, width, 1);
    Mat image_roi = original(roi);
    fftBlock->imageData = (char*)image_roi.data;

    //cvSaveImage("C:/fftBlock1.png", fftBlock);

    cvConvert(fftBlock, imgReal);     

    cvMerge(imgReal, imgImag, NULL, NULL, imgDFT);    
    cvDFT(imgDFT, imgDFT, (CV_DXT_FORWARD | CV_DXT_ROWS));   

    cvSplit(imgDFT, imgReal, imgImag, NULL, NULL);    


    double re,imag;  
    for (int i = 0; i < width; i++)
    { 
        re = ((float*)imgReal->imageData)[i];
        imag = ((float*)imgImag->imageData)[i];
        result[i] = re * re + imag * imag;

    }  

    cvReleaseImage(&imgReal);
    cvReleaseImage(&imgImag);
    cvReleaseImage(&imgDFT);
    cvReleaseImage(&fftBlock);
}

void MakeDFT(Mat original, double* result)
{
    const int width = original.cols;
    const int height = 1;
    Mat fftBlock(1,width, CV_8UC1); 

    Rect roi(0, 0, width, height);
    Mat image_roi = original(roi);
    image_roi.copyTo(fftBlock);     

    //imwrite("C:/fftBlock2.png", fftBlock);

    Mat planes[] = {Mat_<float>(fftBlock), Mat::zeros(fftBlock.size(), CV_32F)};
    Mat complexI; 

    merge(planes, 2, complexI);     
    dft(complexI, complexI, DFT_ROWS); //also tried with DFT_COMPLEX_OUTPUT | DFT_ROWS
    split(complexI, planes); 

    double re, imag; 
    for (int i = 0; i < width; i++)
    {
        re = (float)planes[0].data[i];
        imag = (float)planes[1].data[i];
        result[i] = re * re + imag * imag;      
    } 
}


bool SinusFFTTest()
{ 
    const int size = 1024;
    Mat sinTest(size,size,CV_8UC1, Scalar(0));
    const int n_sin_curves = 10;
    double deg_step = (double)n_sin_curves*360/size;
    for (int j = 0; j < size; j++)
    {
        for (int i = 0; i <size; i++)
        { 
            sinTest.data[j*size+i] = 127.5 * sin(i*deg_step*CV_PI/180) + 127.5; 
        } 
    }

    double* result1 = new double[size];
    double* result2 = new double[size];
    OldMakeDFT(sinTest,result1); 
    MakeDFT(sinTest,result2);
    bool identical = true; 
    for (int i = 0; i < size; i++)
    {
        if (abs(result1[i] - result2[i]) > 1000)
        {
            identical = false;
            break;
        }
    }
    delete[] result1;
    delete[] result2;
    return identical;
}

int _tmain(int argc, _TCHAR* argv[])
{
    if (SinusFFTTest())
    {
        printf("identical");
    }
    else
    {
        printf("different");
    }
    getchar();
    return 0;
}

有人可以解释一下这个区别吗?

2 个答案:

答案 0 :(得分:0)

imgReal - 默认情况下未填充零。

答案 1 :(得分:0)

routing.yml函数中的错误:

MakeDFT()

re = (float)planes[0].data[i]; imag = (float)planes[1].data[i]; 的类型是uchar,它转换为float是不正确的。

修复:

data[i]

在此更改之后,旧版和新版DFT版本会提供相同的结果。或者,您可以使用re = planes[0].at<float>(0,i); imag = planes[1].at<float>(0,i); 代替计算cv::magnitude()re的平方和:

imag

这也给出了与旧cvDFT相同的结果。