【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;
}

输入图片:
【OpenCV4】图像的傅里叶变换 cv::dft() 和逆变换 cv::idft() 解析(c++)_第1张图片
读取灰度图:
【OpenCV4】图像的傅里叶变换 cv::dft() 和逆变换 cv::idft() 解析(c++)_第2张图片
修改宽高
【OpenCV4】图像的傅里叶变换 cv::dft() 和逆变换 cv::idft() 解析(c++)_第3张图片
按照最优的宽高扩展图像
【OpenCV4】图像的傅里叶变换 cv::dft() 和逆变换 cv::idft() 解析(c++)_第4张图片
傅里叶变换结果
【OpenCV4】图像的傅里叶变换 cv::dft() 和逆变换 cv::idft() 解析(c++)_第5张图片
转换成幅值图:

  • 四个角是低频部分,中心是高频部分
    【OpenCV4】图像的傅里叶变换 cv::dft() 和逆变换 cv::idft() 解析(c++)_第6张图片
    最值中心化:
  • 将低频部分移动到中心
    【OpenCV4】图像的傅里叶变换 cv::dft() 和逆变换 cv::idft() 解析(c++)_第7张图片
    傅里叶逆变换结果
    【OpenCV4】图像的傅里叶变换 cv::dft() 和逆变换 cv::idft() 解析(c++)_第8张图片

你可能感兴趣的:(计算机视觉,opencv)