图像傅里叶变换的作用:
- 频谱分析,获取图像中高频低频的分布情况
- 快速卷积,两个矩阵的傅里叶变换结果相乘
案例代码:
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;
}
输入图片:
读取灰度图:
修改宽高
按照最优的宽高扩展图像
傅里叶变换结果
转换成幅值图:
- 四个角是低频部分,中心是高频部分
最值中心化: - 将低频部分移动到中心
傅里叶逆变换结果