Hilbert transform using FFT

asked 2019-10-02 08:58:13 -0600

Czak gravatar image

Im trying to calculate Hilbert transform using openCv base on matlab/ octave code

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

and my c++ code

#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]);

    }
};

After ifft I should obtain shifted by Pi / 2 signal (IMAG) and copy of signal in REAL, but imaginary part is in absolute values

image description

When i run Octave ifft Im getting good answer, and input to function is same. Why there is a difference and how to get result like in Octave (no abs values in imaginary part of signal?

edit retag flag offensive close merge delete