c++ - 如何正确使用opencv在图像上使用傅里叶变换对?

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

最佳答案

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

关于c++ - 如何正确使用opencv在图像上使用傅里叶变换对?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51899579/

相关文章:

c++ - 没有运算符 "<<"与这些操作数匹配,二进制 '>>' : no operator found

c++ - 模板编译失败 : 'double' is not a valid type for a template constant parameter

python - 我在调整 ConvLSTM 模型的大小/输入数组时收到错误消息

opencv - 如何判断处理后图像的色彩空间?

c++ - python 和 weierstrass 函数

c++ - 在 OpenCV 中将 HSV 转换为 RGB 失败

c++ - OpenCV:无法将数据正确传递给函数

java - 如何在java或python中根据一张图像生成不同颜色的图像?

php - 选择 PHP 的图像大小调整算法

c++ - 在 Embarcadero Tools API 中的光标位置插入文本