How do I compute DFT and its reverse with EMGU?

自闭症网瘾萝莉.ら 提交于 2019-12-07 17:26:56

问题


How can I compute the DFT of an image (using EMGU), display it and then compute the reverse to get back to the original?

I'm going to answer my own question here since it took me a while to figure out.


回答1:


To test that it works here's an image


and here's the expected result after applying DFT.

And without further ado here's the code:

// Load image
Image<Gray, float> image = new Image<Gray, float>(@"C:\Users\me\Desktop\lines.png");

// Transform 1 channel grayscale image into 2 channel image
IntPtr complexImage = CvInvoke.cvCreateImage(image.Size, Emgu.CV.CvEnum.IPL_DEPTH.IPL_DEPTH_32F, 2);
CvInvoke.cvSetImageCOI(complexImage, 1); // Select the channel to copy into
CvInvoke.cvCopy(image, complexImage, IntPtr.Zero);
CvInvoke.cvSetImageCOI(complexImage, 0); // Select all channels

// This will hold the DFT data
Matrix<float> forwardDft = new Matrix<float>(image.Rows, image.Cols, 2); 
CvInvoke.cvDFT(complexImage, forwardDft, Emgu.CV.CvEnum.CV_DXT.CV_DXT_FORWARD, 0);

CvInvoke.cvReleaseImage(ref complexImage);

// We'll display the magnitude
Matrix<float> forwardDftMagnitude = GetDftMagnitude(forwardDft); 
SwitchQuadrants(ref forwardDftMagnitude); 

// Now compute the inverse to see if we can get back the original
Matrix<float> reverseDft = new Matrix<float>(forwardDft.Rows, forwardDft.Cols, 2);
CvInvoke.cvDFT(forwardDft, reverseDft, Emgu.CV.CvEnum.CV_DXT.CV_DXT_INV_SCALE, 0);
Matrix<float> reverseDftMagnitude = GetDftMagnitude(reverseDft);    

pictureBox1.Image = image.ToBitmap();
pictureBox2.Image = Matrix2Bitmap(forwardDftMagnitude);
pictureBox3.Image = Matrix2Bitmap(reverseDftMagnitude);

private Bitmap Matrix2Bitmap(Matrix<float> matrix)
{
    CvInvoke.cvNormalize(matrix, matrix, 0.0, 255.0, Emgu.CV.CvEnum.NORM_TYPE.CV_MINMAX, IntPtr.Zero);            

    Image<Gray, float> image = new Image<Gray, float>(matrix.Size);
    matrix.CopyTo(image);

    return image.ToBitmap();
}

// Real part is magnitude, imaginary is phase. 
// Here we compute log(sqrt(Re^2 + Im^2) + 1) to get the magnitude and 
// rescale it so everything is visible
private Matrix<float> GetDftMagnitude(Matrix<float> fftData)
{
    //The Real part of the Fourier Transform
    Matrix<float> outReal = new Matrix<float>(fftData.Size);
    //The imaginary part of the Fourier Transform
    Matrix<float> outIm = new Matrix<float>(fftData.Size);
    CvInvoke.cvSplit(fftData, outReal, outIm, IntPtr.Zero, IntPtr.Zero);

    CvInvoke.cvPow(outReal, outReal, 2.0);
    CvInvoke.cvPow(outIm, outIm, 2.0);

    CvInvoke.cvAdd(outReal, outIm, outReal, IntPtr.Zero);
    CvInvoke.cvPow(outReal, outReal, 0.5);

    CvInvoke.cvAddS(outReal, new MCvScalar(1.0), outReal, IntPtr.Zero); // 1 + Mag
    CvInvoke.cvLog(outReal, outReal); // log(1 + Mag)            

    return outReal;
}

// We have to switch quadrants so that the origin is at the image center
private void SwitchQuadrants(ref Matrix<float> matrix)
{
    int cx = matrix.Cols / 2;
    int cy = matrix.Rows / 2;

    Matrix<float> q0 = matrix.GetSubRect(new Rectangle(0, 0, cx, cy));
    Matrix<float> q1 = matrix.GetSubRect(new Rectangle(cx, 0, cx, cy));
    Matrix<float> q2 = matrix.GetSubRect(new Rectangle(0, cy, cx, cy));
    Matrix<float> q3 = matrix.GetSubRect(new Rectangle(cx, cy, cx, cy));
    Matrix<float> tmp = new Matrix<float>(q0.Size);

    q0.CopyTo(tmp);
    q3.CopyTo(q0);
    tmp.CopyTo(q3);
    q1.CopyTo(tmp);
    q2.CopyTo(q1);
    tmp.CopyTo(q2);
}

Most of the information in this answer is from a question on the OpenCV mailing list and Steve Eddins' article on FFT in image processing.



来源:https://stackoverflow.com/questions/16812950/how-do-i-compute-dft-and-its-reverse-with-emgu

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!