图像处理之频率域与空间域转换(C++)

图像处理之频率域与空间域转换(C++)


前言

频率特征是图像的灰度变化特征。一个重要的经验结论:低频代表图像整体轮廓,高频代表了图像噪声,中频代表图像边缘、纹理等细节。
傅里叶变换进行频域分析的使用场景:
1.具有纹理(条纹)特征的图像,如布匹、木板、纸张等。
2.需要提取对比度低或者信噪比低的特征。
3.图像尺寸较大或者卷积核尺寸大进行滤波时,此时需要转换至频域计算,提高计算速度。(原理:空间域的卷积等价于频率域相乘)


一、原理

基于opencv库实现的空间域和频率域转换,方便进一步对频域分析。

二、空间域到频率域转换

1.代码实现

/*
* @param cv::Mat src	输入图片
* @param cv::Mat dst	输出图片
* @brief 空间域转换到频率域
*/
void Spatial2Frequency(cv::Mat& src,cv::Mat& dst)
{
	// 图像尺寸修正,获得最优的傅里叶变换的尺寸,加快计算
	int h = cv::getOptimalDFTSize(src.rows);
	int w = cv::getOptimalDFTSize(src.cols);

	cv::Mat padImg;
	cv::copyMakeBorder(src, padImg, 0, h - src.rows, 0, w - src.cols, CV_HAL_BORDER_CONSTANT, cv::Scalar(0));

	//构造Mat矩阵的数组存储傅里叶变换后的实数矩阵(planes[0])、虚数矩阵(planes[1])
	cv::Mat planes[] = { cv::Mat_<float>(padImg),cv::Mat::zeros(padImg.size(),CV_32FC1) };
	cv::Mat dftImg;
	cv::merge(planes, 2, dftImg);

	//执行离散傅里叶变换
	cv::dft(dftImg, dftImg);

	//分离dftImg,此时实数矩阵(planes[0])、虚数矩阵(planes[1])
	cv::split(dftImg, planes);

	//定义幅度谱和相位谱
	cv::Mat phaseImg, magnitudeImg;
	cv::phase(planes[0], planes[1], phaseImg);	//此处phaseImg的元素数据类型和planes[0]相同,都是float
	cv::magnitude(planes[0], planes[1], magnitudeImg);//此处magnitudeImg的元素数据类型和planes[0]相同,都是float

	planes[0] = magnitudeImg.clone();
	cv::log(planes[0] + cv::Scalar(1), planes[0]);	//使用对数变换压缩像素值范围,便于可视化

	//交换四个频谱位置进行中心化
	cv::resize(dst, dst, planes[0].size());
	//对四个频谱位置进行交换
	planes[0](cv::Rect(0, 0, planes[0].cols / 2, planes[0].rows / 2)).copyTo(dst(cv::Rect(planes[0].cols / 2, planes[0].rows / 2, planes[0].cols / 2, planes[0].rows / 2)));//左上到右下
	planes[0](cv::Rect(planes[0].cols / 2, 0, planes[0].cols / 2, planes[0].rows / 2)).copyTo(dst(cv::Rect(0, planes[0].rows / 2, planes[0].cols / 2, planes[0].rows / 2)));//右上到左下
	planes[0](cv::Rect(0, planes[0].rows / 2, planes[0].cols / 2, planes[0].rows / 2)).copyTo(dst(cv::Rect(planes[0].cols / 2, 0, planes[0].cols / 2, planes[0].rows / 2)));//左下到右上
	planes[0](cv::Rect(planes[0].cols / 2, planes[0].rows / 2, planes[0].cols / 2, planes[0].rows / 2)).copyTo(dst(cv::Rect(0, 0, planes[0].cols / 2, planes[0].rows / 2)));//右下到左上
	
	cv::normalize(dst, dst, 0, 255, cv::NORM_MINMAX, CV_8UC1);
}
int main()
{
	//读取图片
	string filepath = "F://work_study//algorithm_demo//baby.jpg";
	cv::Mat src = cv::imread(filepath, cv::IMREAD_GRAYSCALE);
	if (src.empty())
	{
		std::cout << "imread error" << std::endl;
		return -1;
	}
	cv::Mat dst(src.size(), src.type());
	
	Spatial2Frequency(src, dst);
	
	//保存图片
	imwrite("dst.bmp", dst);
	cv::waitKey(0);
	return 0;
}

2.结果展示

频率域图片

二、频率域到空间域转换

1.代码实现

/*
* @param cv::Mat src	输入图片
* @param cv::Mat dst	输出图片
* @brief 频率域转换到空间域
*/
void Frequency2Spatial(cv::Mat& src, cv::Mat& dst)
{
	// 图像尺寸修正,获得最优的傅里叶变换的尺寸,加快计算
	int h = cv::getOptimalDFTSize(src.rows);
	int w = cv::getOptimalDFTSize(src.cols);

	cv::Mat padImg;
	cv::copyMakeBorder(src, padImg, 0, h - src.rows, 0, w - src.cols, CV_HAL_BORDER_CONSTANT, cv::Scalar(0));

	//构造Mat矩阵的数组存储傅里叶变换后的实数矩阵(planes[0])、虚数矩阵(planes[1])
	cv::Mat planes[] = { cv::Mat_<float>(padImg),cv::Mat::zeros(padImg.size(),CV_32FC1) };
	cv::Mat dftImg;
	cv::merge(planes, 2, dftImg);

	//执行离散傅里叶变换
	cv::dft(dftImg, dftImg);

	//分离dftImg,此时实数矩阵(planes[0])、虚数矩阵(planes[1])
	cv::split(dftImg, planes);

	//定义幅度谱和相位谱
	cv::Mat phaseImg, magnitudeImg;
	cv::phase(planes[0], planes[1], phaseImg);	//此处phaseImg的元素数据类型和planes[0]相同,都是float
	cv::magnitude(planes[0], planes[1], magnitudeImg);//此处magnitudeImg的元素数据类型和planes[0]相同,都是float
	
	//傅里叶逆变换,实现从频率域到空间域转换
	cv::Mat idftImg;
	//通过幅度谱和相位谱恢复实部planes[0]虚部planes[1]
	//cv::polarToCart(magnitudeImg, phaseImg, planes[0], planes[1]);
	cv::merge(planes, 2, idftImg);
	cv::dft(idftImg, idftImg, CV_HAL_DFT_INVERSE | CV_HAL_DFT_REAL_OUTPUT);
	cv::normalize(idftImg, idftImg, 0, 255, cv::NORM_MINMAX, CV_8U);
	dst=idftImg(cv::Rect(0, 0, src.cols & -2, src.rows & -2));	//此处按位与的意思是为了把长宽调整为2的倍数
}
int main()
{
	//读取图片
	string filepath = "F://work_study//algorithm_demo//baby.jpg";
	cv::Mat src = cv::imread(filepath, cv::IMREAD_GRAYSCALE);
	if (src.empty())
	{
		std::cout << "imread error" << std::endl;
		return -1;
	}

	cv::Mat dst(src.size(), src.type());
	
	Frequency2Spatial(src,dst);
	
	//保存图片
	cv::imwrite("idftImg.bmp", dst);
	cv::waitKey(0);
	return 0;
}

2.结果展示

傅里叶反变换的结果

总结

本文主要实现了在opencv库使用C++下实现空间域和频率域的相互转换,后续更新空间域转换到频率域的应用。
因为笔者水平有限,有错误欢迎指出,代码本人均在本地运行实验正确,大家放心使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值