【OpenCV4】图像的傅里叶变换 cv::dft() 和逆变换 cv::idft() 解析(c++)

图像傅里叶变换的作用:

  • 频谱分析,获取图像中高频低频的分布情况
  • 快速卷积,两个矩阵的傅里叶变换结果相乘

案例代码:

cv::Mat TestOpencvDft()
{
    cv::Mat lena = cv::imread("lena.jpg", 0);
    cv::resize(lena, lena, cv::Size(501, 501));

    // 确定适合做傅里叶变换的图像最佳尺寸
    int rows = cv::getOptimalDFTSize(lena.rows);
    int cols = cv::getOptimalDFTSize(lena.cols);

    // 扩展图像
    cv::Mat lena_pad;
    int up = (rows - lena.rows) / 2;
    int down = rows - lena.rows - up;
    int left = (cols - lena.cols) / 2;
    int right = cols - lena.cols - left;
    cv::copyMakeBorder(lena, lena_pad, up, down, left, right, cv::BORDER_CONSTANT);

    // 构建输入
    cv::Mat channels[2], complex;
    channels[0] = cv::Mat_<float>(lena_pad); // 构建实数部分
    channels[1] = cv::Mat::zeros(lena_pad.size(), CV_32FC1); // 构建虚数部分
    cv::merge(channels, 2, complex); // 构建复数矩阵

    // 离散傅里叶变换
    cv::Mat lena_dft;
    cv::dft(complex, lena_dft);

    // 拆分实数部分和虚数部分,将复数转化为幅值
    cv::Mat result_channels[2];
    cv::split(lena_dft, result_channels);
    cv::Mat amplitude;
    cv::magnitude(result_channels[0], result_channels[1], amplitude);
    
    // 将幅值进行对数缩小,公式: amp = log(amp+1),这里 +1 是为了防止有小于 1 的值转换后形成负数
    amplitude += 1;
    log(amplitude, amplitude);

    // 截取和原图对应的区域
    amplitude = amplitude(cv::Rect(up, left, lena.cols, lena.rows));
    cv::normalize(amplitude, amplitude, 0, 1, cv::NORM_MINMAX);

    // 最值中心化
    int center_x = amplitude.cols / 2;
    int center_y = amplitude.rows / 2;
    // 分解成 4 个象限
    cv::Mat up_left = amplitude(cv::Rect(0, 0, center_x, center_y));
    cv::Mat up_right = amplitude(cv::Rect(center_x, 0, center_x, center_y));
    cv::Mat down_left = amplitude(cv::Rect(0, center_y, center_x, center_y));
    cv::Mat down_right = amplitude(cv::Rect(center_x, center_y, center_x, center_y));
    // 对角区域调换
    cv::Mat temp;
    temp = up_left.clone();
    down_right.copyTo(up_left);
    temp.copyTo(down_right);

    temp = up_right.clone();
    down_left.copyTo(up_right);
    temp.copyTo(down_left);

    // 傅里叶逆变换
    cv::Mat re;
    cv::idft(lena_dft, re, cv::DFT_SCALE);
    cv::Mat re_channels[2];
    cv::split(re, re_channels);

    cv::Mat result;
    re_channels[0].convertTo(result, CV_8UC1);
    return result;
}

输入图片:
请添加图片描述
读取灰度图:
请添加图片描述
修改宽高
请添加图片描述
按照最优的宽高扩展图像
请添加图片描述
傅里叶变换结果
在这里插入图片描述
转换成幅值图:

  • 四个角是低频部分,中心是高频部分
    在这里插入图片描述
    最值中心化:
  • 将低频部分移动到中心
    在这里插入图片描述
    傅里叶逆变换结果
    请添加图片描述
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值