1

Platform: opencv 2.4.9 on win7 with VC2015

Issue:

Input image DFT magnitude image

  1. strange noise:

I use dft transfer image into frequency domain and transfer back by idft. I use 2 ways to get the result. convertTo() and normalize(). the result by convertTo() has strange noise.

normalize() result ........... .......... ......................convertTo() result

  1. wrong high pass filter result:

I pass dft image(both Re & Im) through a Gaussian High Pass Filter and the result. convertTo() and normalize() are totally different. convertTo() seem right but has noise and normalize() is strange but no noise...

high pass filter image for display

normalize() result of high pass filter result..... convertTo() result of high pass filter result

Code:

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

#include <iostream>

using namespace cv;
using namespace std;

void DFT_Shift(Mat &a_tImage)
{
// rearrange the image so that the origin is at the image center
int cx = a_tImage.cols / 2;
int cy = a_tImage.rows / 2;

Mat q0(a_tImage, Rect(0, 0, cx, cy));   // Top-Left - Create a ROI per quadrant
Mat q1(a_tImage, Rect(cx, 0, cx, cy));  // Top-Right
Mat q2(a_tImage, Rect(0, cy, cx, cy));  // Bottom-Left
Mat q3(a_tImage, Rect(cx, cy, cx, cy)); // Bottom-Right

Mat tmp;                           // swap quadrants (Top-Left with Bottom-Right)
q0.copyTo(tmp);
q3.copyTo(q0);
tmp.copyTo(q3);

q1.copyTo(tmp);                    // swap quadrant (Top-Right with Bottom-Left)
q2.copyTo(q1);
tmp.copyTo(q2);
}

int main()
{
Mat I = imread("Src.bmp", CV_LOAD_IMAGE_GRAYSCALE);
if (I.empty())
    return -1;

Mat padded;                             // expand input image to optimal size
int m = getOptimalDFTSize(I.rows);
int n = getOptimalDFTSize(I.cols);      // on the border add zero values
copyMakeBorder(I, padded, 0, m - I.rows, 0, n - I.cols, BORDER_CONSTANT, Scalar::all(0));

Mat planes[] = { Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F) };
#if DO_GHPF > 0
Mat tPlanesFilter[] = { Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F) };
#endif

Mat complexI;
merge(planes, 2, complexI);         // Add to the expanded another plane with zeros
dft(complexI, complexI);            // this way the result may fit in the source matrix
                                    // compute the magnitude and switch to logarithmic scale
                                    // => log(1 + sqrt(Re(DFT(I))^2 + Im(DFT(I))^2))
split(complexI, planes);            // planes[0] = Re(DFT(I), planes[1] = Im(DFT(I))

// Pass both Re & Im Planes through Gaussian High Pass Filter
#if DO_GHPF > 0
GaussianHighPassFilter(complexI, tPlanesFilter);
#endif

Mat magI = planes[0];
printf("Re: %f\n", planes[0].at<float>(40, 40));
printf("Im: %f\n", planes[1].at<float>(40, 40));
magnitude(magI, planes[1], planes[0]);  // planes[0] = magnitude

// switch to logarithmic scale
magI += Scalar::all(1);                    
log(magI, magI);

// crop the spectrum, if it has an odd number of rows or columns
magI = magI(Rect(0, 0, magI.cols & -2, magI.rows & -2));

// dft data base should be shifted to image's center
DFT_Shift(magI);

// Transform the matrix with float values into a viewable image form (float between values 0 and 1).
normalize(magI, magI, 0, 1, CV_MINMAX); 

imshow("Input Image", I);    // Show the result
imshow("spectrum magnitude", magI);

magI = magI * 255;
imwrite("./Magnitude.jpg", magI);

#if 1   // test idft
Mat ifft;
idft(complexI, ifft, DFT_REAL_OUTPUT);

Mat ifftConvert;
ifft.convertTo(ifftConvert, CV_8U);
imwrite("./IDFT_CV_8U.jpg", ifft);

normalize(ifft, ifft, 0, 1, CV_MINMAX);
imshow("IDFT", ifft);

ifft = ifft * 255;
imwrite("./IDFT.jpg", ifft);
#endif
waitKey();

return 0;
}
francis
  • 9,525
  • 2
  • 25
  • 41
Chi-Fang Hsieh
  • 235
  • 1
  • 3
  • 13

1 Answers1

1

The backward Fourier Transform is not normalized. Indeed, if the image is 512x512, idft(dft(x)) is 512x512 times bigger than x. The strange noise is due to the fact that numbers are not in the range 0 - 255 anymore.

In particular, the backward dft features negative values and values as large as 6.6e7. It can be checked by adding:

double min, max;
cv::minMaxLoc(ifft, &min, &max);
std::cout << min<< " " << max <<std::endl;

Scaling down the backward dft can be done by adding:

ifft=ifft/(512*512);

The strange noise is removed.

2/ the normalize() result of high pass filter seems correct. Such a filter will substract a blured image from the original image. In particular, the average of the ouput is 0. Hence, it features negative and positive values. Since the maximum and minimum are of the same magnitude in your case, normalize() will set the zero value near 127\approx 255/2. This is the reason why the image becomes grey. White values correspond to positive values and black values to negative ones.

convertTo() will get very large negative and positive values out of the range 0 -255 for the edges. These values will be converted to white. Far from the edges, the values are close to zero and the color remains black.

francis
  • 9,525
  • 2
  • 25
  • 41
  • Thanks @francis So if I want to let smooth region into 0 by high pass filter. Then I have to use abs() to modify the negative value before normalize()? – Chi-Fang Hsieh Jun 13 '16 at 02:55
  • You're welcome ! Indeed, computing the absolute value before normalizing will highlight the edges and you will get something similar to the initial result of the `convertTo()`. – francis Jun 13 '16 at 07:13