繁体   English   中英

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

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

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

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

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。 因此,应保留复数输出的实部。 如果采用幅度,则将获得实数分量的绝对值,这意味着原始输入中的任何负值将在最终输出中变为正值。 在示例图像的情况下,所有像素都是非负的,但这不一定是正确的。 做正确的事情,取真实的分量而不是幅度。

暂无
暂无

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

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