简体   繁体   English

如何正确使用opencv在图像上使用傅立叶变换对?

[英]How to use fourier transform pair on image using opencv correctly?

Firstly, I utilize putText function to create a zero-filled image: 首先,我利用putText函数创建一个零填充图像:

std::string text("Mengranlin");
int rows = 222;
int cols = 112;
double textSize = 1.5;
int textWidth = 2;
int num = 255;
cv::Mat zero_filled_img = cv::Mat::zeros(cols, rows, CV_32F);
putText(zero_filled_img, text, 
cv::Point(zero_filled_img.cols * 0.5, 
zero_filled_img.rows * 0.3),
cv::FONT_HERSHEY_PLAIN, textSize, cv::Scalar(num, num, num), textWidth);
cv::Mat zero_filled_img2;
flip(zero_filled_img, zero_filled_img2, -1);
zero_filled_img += zero_filled_img2;
transpose(zero_filled_img, zero_filled_img);
flip(zero_filled_img, zero_filled_img, 1);

Here is the image: 这是图片:

sssssss

Secondly, I utilize inverse Fourier transform to the image: 其次,我对图像进行傅立叶逆变换:

int m = getOptimalDFTSize(rows);
int n = getOptimalDFTSize(cols);
cv::Mat dst;
copyMakeBorder(zero_filled_img, dst, 0, m - rows, 0, n - cols, BORDER_CONSTANT, Scalar::all(0));
cv::Mat planes[] = { cv::Mat_<float>(dst), 
cv::Mat::zeros(dst.size(), CV_32F) };
cv::Mat complex;
cv::merge(planes,2, complex);
idft(complex, complex);
split(complex, planes);
magnitude(planes[0], planes[1], planes[0]);

Thirdly, I utilize Fourier transform to the result of inverse Fourier transform: 第三,我将傅里叶变换用于傅里叶逆变换的结果:

cv::merge(planes2, 2, complex);
dft(complex, complex);
split(complex, planes2);
magnitude(planes2[0], planes2[1], planes2[0]);
cv::Mat result = planes2[0];

Finally, I save the image: 最后,我保存图像:

result += 1;
log(result, result);
result = result(cv::Rect(0, 0, cols, rows));
int cx = result.cols / 2;
int cy = result.rows / 2;
cv::Mat temp;
cv::Mat q0(result, cv::Rect(0, 0, cx, cy));
cv::Mat q1(result, cv::Rect(cx, 0, cx, cy));
cv::Mat q2(result, cv::Rect(0, cy, cx, cy));
cv::Mat q3(result, cv::Rect(cx, cy, cx, cy));
q0.copyTo(temp);
q3.copyTo(q0);
temp.copyTo(q3);
q1.copyTo(temp);
q2.copyTo(q1);
temp.copyTo(q2);
imwrite("./image/log_result.jpg", result);

Here is the image: 这是图片:

sssssss

Although the "Mengnalin" can be found from the image, that is very weak. 尽管从图像中可以找到“孟纳林”,但这非常薄弱。 And then, I save the normalization of the result, but I found nothing: 然后,我保存结果的归一化,但未发现任何结果:

normalize(result, result);
imwrite("./image/normalize_result.jpg", result);
result *= 255;
imwrite("./image/normalize_result255.jpg", result);

Here is the normalization image: 这是标准化图像:

sssssss

Here is the normalization image x 255: 这是归一化图像x 255:

sssssss

The experiment is successful when using Matlab. 使用Matlab时实验成功。 I want to know where the error is? 我想知道错误在哪里?

Below is the complete code that I ran: 以下是我运行的完整代码:

std::string text("Mengranlin");
int rows = 222;
int cols = 112;
double textSize = 1.5;
int textWidth = 2;
int num = 255;
cv::Mat zero_filled_img = cv::Mat::zeros(cols, rows, CV_32F);
putText(zero_filled_img, text, cv::Point(zero_filled_img.cols * 0.5, zero_filled_img.rows * 0.3),
    cv::FONT_HERSHEY_PLAIN, textSize, cv::Scalar(num, num, num), textWidth);
cv::Mat zero_filled_img2;
flip(zero_filled_img, zero_filled_img2, -1);
zero_filled_img += zero_filled_img2;
transpose(zero_filled_img, zero_filled_img);
flip(zero_filled_img, zero_filled_img, 1);
cv::Mat de = cv::Mat_<uchar>(zero_filled_img);
cv::imwrite("./image/zero_filled_img.jpg", zero_filled_img);

//idft
int m = getOptimalDFTSize(rows);
int n = getOptimalDFTSize(cols);
cv::Mat dst;
copyMakeBorder(zero_filled_img, dst, 0, m - rows, 0, n - cols, BORDER_CONSTANT, Scalar::all(0));
cv::Mat planes[] = { cv::Mat_<float>(dst), cv::Mat::zeros(dst.size(), CV_32F) };
cv::Mat complex;
cv::merge(planes,2, complex);
idft(complex, complex);
split(complex, planes);
magnitude(planes[0], planes[1], planes[0]);
cv::Mat freq = planes[0];
freq = freq(cv::Rect(0, 0, cols, rows));
normalize(freq, freq, 0, 1, CV_MINMAX);

//dft
cv::Mat planes2[] = {planes[0], planes[1]};
cv::merge(planes2, 2, complex);
dft(complex, complex);
split(complex, planes2);
magnitude(planes2[0], planes2[1], planes2[0]);
cv::Mat result = planes2[0];
//float min_v, max_v; min_max(result, min_v, max_v);
imwrite("./image/img.jpg", result);
result += 1;
imwrite("./image/img_plus_zero.jpg", result);
log(result, result);
result = result(cv::Rect(0, 0, cols, rows));
//float min_v1, max_v1; min_max(result, min_v1, max_v1);
imwrite("./image/log_img.jpg", result);
int cx = result.cols / 2;
int cy = result.rows / 2;
cv::Mat temp;
cv::Mat q0(result, cv::Rect(0, 0, cx, cy));
cv::Mat q1(result, cv::Rect(cx, 0, cx, cy));
cv::Mat q2(result, cv::Rect(0, cy, cx, cy));
cv::Mat q3(result, cv::Rect(cx, cy, cx, cy));
q0.copyTo(temp);
q3.copyTo(q0);
temp.copyTo(q3);
q1.copyTo(temp);
q2.copyTo(q1);
temp.copyTo(q2);
normalize(result, result);
imwrite("./image/normalize_img.jpg", result);
result *= 255;
imwrite("./image/normalize_img255.jpg", result);

Your code splits the output of idft into planes[0] (real component) and planes[1] (imaginary component), then computes the magnitude and writes it to planes[0] : 您的代码将idft的输出idftplanes[0] (实数部分)和planes[1] (虚数部分),然后计算幅度并将其写入planes[0]

idft(complex, complex);
split(complex, planes);
magnitude(planes[0], planes[1], planes[0]);

Next, you merge planes[0] and planes[1] as the real and imaginary parts of a complex-valued image, and compute the dft : 接下来,将planes[0]planes[1]合并为复数值图像的实部和虚部,并计算dft

cv::Mat planes2[] = {planes[0], planes[1]};
cv::merge(planes2, 2, complex);
dft(complex, complex);

But because planes[0] doesn't contain the real part of the output of idft any more, but its magnitude, dft will not perform the inverse calculation that idft did. 但是,由于planes[0]不再包含idft输出的实部,而是其大小,因此dft将不会执行idft所做的逆计算。

You can fix this easily. 您可以轻松解决此问题。 Instead of: 代替:

magnitude(planes[0], planes[1], planes[0]);
cv::Mat freq = planes[0];

Do: 做:

cv::Mat freq;
magnitude(planes[0], planes[1], freq);

You can significantly simplify your code. 您可以大大简化您的代码。 Try the following code ( zero_filled_img is the input image computed earlier): 尝试以下代码( zero_filled_img是之前计算出的输入图像):

// DFT
cv::Mat complex;
dft(zero_filled_img, complex, DFT_COMPLEX_OUTPUT);

// IDFT
cv::Mat result;
idft(complex, result, DFT_REAL_OUTPUT);
imwrite("./image/img.jpg", result);

result should be equal to zero_filled_img within numerical accuracy. result应在数值精度范围内等于zero_filled_img

The DFT_COMPLEX_OUTPUT flag forces the creation of a full, complex-valued DFT, even though the input array is real-valued. 即使输入数组是实数值, DFT_COMPLEX_OUTPUT标志也将强制创建完整的,复数值的DFT。 Likewise, DFT_REAL_OUTPUT causes any imaginary output components to be dropped, this is equivalent to computing the complex IDFT and then taking the real part only. 同样, DFT_REAL_OUTPUT导致任何虚构的输出分量都被丢弃,这等效于计算复杂的IDFT,然后仅取实部。

I have reversed the DFT and IDFT to be conceptually correct (though it is perfectly fine to reverse these two operations). 我已经将DFT和IDFT颠倒了以在概念上是正确的(尽管颠倒这两个操作是完全可以的)。 DFT_COMPLEX_OUTPUT only works with the forward transform and DFT_REAL_OUTPUT only works with the inverse transform, so the code above will not work (I believe) if you use these two operations in the order you attempted in your own code. DFT_COMPLEX_OUTPUT仅适用于正向变换,而DFT_REAL_OUTPUT仅适用于逆向变换,因此,如果您按照在自己的代码中尝试的顺序使用这两个操作,则上面的代码将不起作用(我相信)。

The code above also doesn't bother with padding to a favourable size. 上面的代码也不用填充到合适的大小。 Doing so might reduce computation time, but for such a small image it will not matter at all. 这样做可能会减少计算时间,但是对于如此小的图像,这根本不重要。


Note also that taking the magnitude of the output of the inverse transform (the second transform you apply) is OK in your case, but not in general. 还要注意,在您的情况下,取逆变换(您应用的第二个变换)的输出幅度是可以的,但通常不行。 This second transform is expected to produce a real-valued output (since the input to the first one was real-valued). 预计第二个转换将产生实值输出(因为第一个转换的输入是实值)。 Any imaginary component should be 0 within numerical precision. 在数值精度内,任何虚部都应为0。 Thus, the real component of the complex output should be kept. 因此,应保留复数输出的实部。 If you take the magnitude, you obtain the absolute value of the real component, meaning that any negative values in the original input will become positive values in the final output. 如果采用幅度,则将获得实数分量的绝对值,这意味着原始输入中的任何负值将在最终输出中变为正值。 In the case of the example images, all pixels are non-negative, but this is not necessarily true. 在示例图像的情况下,所有像素都是非负的,但这不一定是正确的。 Do the correct thing and take the real component rather than the magnitude. 做正确的事情,取真实的分量而不是幅度。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM