图像处理-Opencv入门(4)-频域处理基础
作者:互联网
一、图像的频域处理
1.1 图像的频域处理的概念
图像的频域处理即将图像变换到频域中,然后在频域中对图像进行处理,其特点是运算速度快。
频域处理的首要步骤就是将图像由时域变换到频域,因此,各种变换是图像处理研究的基础。
1.2 离散傅里叶变换(DFT)
傅里叶变换在时域和频域上都呈现离散的形式, 将时域信号的采样变换为在离散时间傅里叶变换频域的采样。
1.3 傅立叶变换图像处理实例-Opencv
1.3.1 主函数
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
using namespace std;
using namespace cv;
// 函数声明
void ImgDFT(Mat& inputImag_1, Mat&outputImg);
int main()
{
double dx = 1.5, dy = 1.5; // 缩放系数
// 载入图像并显示
Mat originImage_boy = imread("baby.png", 1);
imshow("original_boy", originImage_boy);
if (originImage_boy.empty()) {
return -1;
}
// 创建效果图
Mat resultImage;
// resultImage.create(round(originImage_boy.rows), round(originImage_boy.cols), originImage_boy.type());
// 记录时间
double timeClock = static_cast<double>(getTickCount());
// 函数调用
// 可定义和调用不同的函数
ImgDFT(originImage_boy, resultImage);
// 输出时间
timeClock = ((double)getTickCount() - timeClock) / getTickCount();
cout << "run time:" << timeClock << "seconds" << endl;
// imshow("result",resultImage);
waitKey(0);
return 0;
}
1.3.1 图像的离散傅里叶变换函数
// 函数定义
// 使用动态地址计算图像
void ImgDFT(Mat& inputImag_1, Mat& outputImg) {
Mat srcGray;
cvtColor(inputImag_1, srcGray, CV_RGB2GRAY);
int m = getOptimalDFTSize(srcGray.rows);
int n = getOptimalDFTSize(srcGray.cols);
Mat padded;
//【1】把灰度图像放扩展到最佳尺寸,在右边和下边扩展图像,扩展边界部分填充为0;
copyMakeBorder(srcGray, padded, 0, m - srcGray.rows,0, n - srcGray.cols, BORDER_CONSTANT, Scalar::all(0));
cout<<padded.size()<<endl;
//【2】为傅里叶变换的结果分配存储空间。
//这里是获取了两个Mat,一个用于存放dft变换的实部,一个用于存放虚部,初始的时候,实部就是图像本身,虚部全为零
Mat planes[] = {Mat_<float>(padded), Mat::zeros(padded.size(),CV_32F)};
Mat complexImg;
//将几个单通道的mat融合成一个多通道的mat,这里融合的complexImg既有实部又有虚部
merge(planes,2,complexImg);
// 【3】进行离散傅里叶变换
//对上边合成的mat进行傅里叶变换,支持原地操作,傅里叶变换结果为复数.通道1存的是实部,通道二存的是虚部
dft(complexImg,complexImg);
//把变换后的结果分割到两个mat,一个实部,一个虚部,方便后续操作
// 【4】复数转换为幅值
split(complexImg,planes);
// 【5】尺度缩放
//这一部分是为了计算dft变换后的幅值,傅立叶变换的幅度值范围大到不适合在屏幕上显示。高值在屏幕上显示为白点,而低值为黑点,高低值的变化无法有效分辨。为了在屏幕上凸显出高低变化的连续性,我们可以用对数尺度来替换线性尺度,以便于显示幅值,计算公式如下:
//=> log(1 + sqrt(Re(DFT(I))^2 +Im(DFT(I))^2))
magnitude(planes[0],planes[1],planes[0]);
Mat mag = planes[0];
mag += Scalar::all(1);
log(mag, mag);
// 【6】剪切和重分布幅度图象限
//crop the spectrum, if it has an odd number of rows or columns
//修剪频谱,如果图像的行或者列是奇数的话,那其频谱是不对称的,要修剪
mag = mag(Rect(0, 0, mag.cols & -2, mag.rows & -2));
Mat _magI = mag.clone();
//这一步的目的仍然是为了显示,但是幅度值仍然超过可显示范围[0,1],我们使用 normalize() 函数将幅度归一化到可显示范围。
normalize(_magI, _magI, 0, 1, CV_MINMAX);
imshow("before rearrange", _magI);
//rearrange the quadrants of Fourier image
//so that the origin is at the image center
// 【7】重新分配象限,使(0,0)移动到图像中心,
//在《数字图像处理》中,傅里叶变换之前要对源图像乘以(-1)^(x+y)进行中心化。
//这是是对傅里叶变换结果进行中心化
int cx = mag.cols/2;
int cy = mag.rows/2;
Mat tmp;
Mat q0(mag, Rect(0, 0, cx, cy)); //Top-Left - Create a ROI per quadrant
Mat q1(mag, Rect(cx, 0, cx, cy)); //Top-Right
Mat q2(mag, Rect(0, cy, cx, cy)); //Bottom-Left
Mat q3(mag, Rect(cx, cy, cx, cy)); //Bottom-Right
//swap quadrants(Top-Left with Bottom-Right)
q0.copyTo(tmp);
q3.copyTo(q0);
tmp.copyTo(q3);
// swap quadrant (Top-Rightwith Bottom-Left)
q1.copyTo(tmp);
q2.copyTo(q1);
tmp.copyTo(q2);
// 【8】归一化,用0到1之间的浮点值将矩阵变换为可视的图像格式
normalize(mag,mag, 0, 1, NORM_MINMAX);
imshow("Input Image", srcGray);
imshow("spectrum magnitude Image",mag);
//傅里叶的逆变换
Mat ifft;
idft(complexImg,ifft,DFT_REAL_OUTPUT);
normalize(ifft,ifft,0,1,CV_MINMAX);
imshow("inverse fft Image",ifft);
}
1.3.3 图像傅里叶变换结果图
标签:Mat,变换,频域,Opencv,图像处理,mag,图像,傅里叶 来源: https://blog.csdn.net/weixin_39445525/article/details/100139631