其他分享
首页 > 其他分享> > 图像处理-Opencv入门(4)-频域处理基础

图像处理-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