使用FFT的希尔伯特变换

时间:2019-10-02 15:40:38

标签: c++ matlab fft

我正在尝试使用基于matlab /倍频程代码的openCv计算希尔伯特变换

function y = hilbert(x)
 if nargin != 1, usage("y = hilbert(x)"); endif
 if !isreal(x), error("hilbert: requires real input vector"); endif
 transpose = rows(x)==1;
 if transpose, x=x.'; endif
 [r, c] = size(x);
 n=2^nextpow2(r);
 if r < n, x = [ x ; zeros(n-r, c) ]; endif
 y = fft(x);
 y = ifft([y(1,:) ; 2*y(2:n/2,:) ; y(n/2+1,:) ; zeros(n/2-1,columns(y))]);
 if r < n, y(r+1:n,:) = []; endif
 if transpose, y = y.'; endif
endfunction

和我的c ++代码

#include <opencv2/core.hpp>
#include <opencv2/core/eigen.hpp>
#include "Eigen/Dense"
class HilbertTransformTest{

private:

cv::Mat CreateFilter(cv::Mat &data)const {
    cv::Mat factor = cv::Mat::ones( data.rows, data.cols, CV_32FC2 );

    for (int i=0; i<data.rows; ++i){
        for (int j=1; j<data.cols/2; ++j){
            factor.at<cv::Vec2f>(i, j)[0] = 2;
            factor.at<cv::Vec2f>(i, j)[1] = 2;
            factor.at<cv::Vec2f>(i, data.cols-j)[0] = 0;
            factor.at<cv::Vec2f>(i, data.cols-j)[1] = 0;
        }
    }
    return factor;
}

cv::Mat GetComplexMat(cv::Mat &Data) const {
    cv::Mat planes[] = {cv::Mat_<float>(Data), cv::Mat::zeros(Data.size(), CV_32F)};
    cv::Mat complexI;
    cv::merge(planes, 2, complexI);
    return complexI;
}

cv::Mat GenerateData() const {
    Eigen::Matrix<float, -1, -1, Eigen::RowMajor> Data(1, 256);
    cv::Mat Vis;
    for (int iter = 0; iter < Data.cols(); ++iter) {
        double t = double(iter) / 255.0 * 10.0;
        Data(0, iter) = std::sin(2 * CV_PI * 0.5 * t);
    }
    cv::eigen2cv(Data, Vis);
    return Vis;
}

public:
HilbertTransformTest() {

    cv::Mat Data = GenerateData();
    cv::Mat Kernel = CreateFilter(Data);
    cv::Mat ComplexData = GetComplexMat(Data);
    cv::Mat rfSpectrum;
    cv::dft(ComplexData, rfSpectrum, cv::DFT_COMPLEX_OUTPUT);
    cv::multiply(rfSpectrum, Kernel, rfSpectrum, 1.0, CV_32FC2);
    cv::idft(rfSpectrum, ComplexData,  cv::DFT_ROWS + cv::DFT_COMPLEX_OUTPUT + cv::DFT_SCALE);

    cv::Mat planes[2];
    cv::split(ComplexData, planes);
    cv::Mat REAL = planes[0];
    cv::Mat IMAG = cv::abs(planes[1]);

}
};

在iftf之后,我应获得Pi / 2信号(IMAG)的偏移并以REAL形式复制信号,但虚部为绝对值。我检查了matalb代码,直到ifft为止一切都是一样的,并且返回了(在八度音阶中)很好的虚部,但是openCV ifft仅创建了正值。

enter image description here

0 个答案:

没有答案