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

时间:2018-08-17 16:28:42

标签: c++ opencv image-processing dft

首先,我利用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);

这是图片:

sssssss

第二,我对图像进行傅立叶逆变换:

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::merge(planes2, 2, complex);
dft(complex, complex);
split(complex, planes2);
magnitude(planes2[0], planes2[1], planes2[0]);
cv::Mat result = planes2[0];

最后,我保存图像:

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

这是图片:

sssssss

尽管从图像中可以找到“孟纳林”,但这非常微弱。然后,我保存结果的归一化,但未发现任何结果:

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

这是归一化图像:

sssssss

这是归一化图像x 255:

sssssss

使用Matlab时,实验成功。我想知道错误在哪里?

下面是我运行的完整代码:

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

1 个答案:

答案 0 :(得分:0)

您的代码将idft的输出分为planes[0](实数部分)和planes[1](虚数部分),然后计算幅度并将其写入planes[0]:< / p>

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

接下来,您将planes[0]planes[1]合并为复数值图像的实部和虚部,然后计算dft

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

但是,由于planes[0]不再包含idft的输出的实部,而是包含其幅度,因此dft将不会执行idft的反计算做到了。

您可以轻松解决此问题。代替:

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

要做:

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

您可以大大简化您的代码。尝试以下代码(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在数值精度上应等于zero_filled_img

即使输入数组是实值,DFT_COMPLEX_OUTPUT标志也将强制创建完整的,复数值的DFT。同样,DFT_REAL_OUTPUT会导致任何虚构的输出分量丢失,这等效于计算复杂的IDFT,然后仅取实部。

我已将DFT和IDFT颠倒为概念上正确的(尽管颠倒这两个操作是完全可以的)。 DFT_COMPLEX_OUTPUT仅适用于正向变换,而DFT_REAL_OUTPUT仅适用于逆向变换,因此,如果您按照在自己的代码中尝试的顺序使用这两个操作,则上面的代码将不起作用(我相信) 。

上面的代码也不用填充到合适的大小。这样做可能会减少计算时间,但是对于如此小的图像,这根本没有关系。


还要注意,在您的情况下,取逆变换(您应用的第二个变换)的输出幅度是可以的,但通常不行。预计第二个转换将产生实值输出(因为第一个转换的输入是实值)。在数值精度内,任何虚部都应为0。因此,应保留复数输出的实部。如果采用幅度,则将获得实数分量的绝对值,这意味着原始输入中的任何负值将在最终输出中变为正值。在示例图像的情况下,所有像素都是非负的,但这不一定是正确的。做正确的事情,并取真实成分而不是幅度。