DFT参数介绍及在图像卷积中的应用

前情提要

为啥我要在另一篇博客里已经详细写过DFT的情况下另起一篇单独介绍呢,这是因为我发现站内很多博客都没有对DFT的参数及输出值的一个点给出明确解释:就是在对某张图像进行傅立叶变换时需要对其进行通道扩充以满足变换后有实部虚部的需求,而在图像卷积时却直接对原图(单通道灰度)图进行傅立叶变换即可。
为了方便后人的查找,单独列出来供大家参考。

大纲

  1. dft参数介绍
  2. 示例代码

参数介绍
DFT原型如下:

dft(InputArray src, OutputArray dst, int flags = 0, int nonzeroRows = 0);

第一个参数为待变换的时域图像;
第二个参数为储存变换结果的频域矩阵;
(注意通常情况下上述两参数都应该为双通道的矩阵,两通道分别保存实部和虚部 ,即使我们的图像都是实数也要分成复数的形式;因为如果src值只用单通道矩阵的,输出结果会采用CCS(复共轭对称)的压缩格式输出为单通道,即:在这里插入图片描述
详情查看dft官方文档:opencv官方文档

第三个参数为变换标识符,默认取零为正向变换,取其他值时:
在这里插入图片描述
第四个值不为0时,函数会默认只有输入矩阵的前nonzeroRows行(未设置DFT_INVERSE)是非零行,或者只有输出矩阵的前nonzeroRows(设置了DFT_INVERSE)行是非零行,因此,函数在处理剩余行是可以节省一些时间,这项技术在采用DFT计算矩阵卷积时尤为明显,通常我们会去这个值为src.rows;
通过上述参数介绍我们了解到:如果需要得到图像完整的频域图像,就需要构造双通道的矩阵以满足傅立叶变换实部虚部的要求,如果只是为图像卷积做准备工作的话就只需要得到CCS压缩之后的频域图像,后续使用mulSpectrums()就可以计算CCS压缩格式矩阵的逐元素乘法了。
mulSpectrums()函数官方文档介绍为:
在这里插入图片描述
二、示例代码

void convolveDFT(Mat A, Mat B, Mat &C)
{
	//初始化输出矩阵
	//这里对矩阵的卷积操作是舍弃边界部分的卷积操作,所以最终输出图像的大小和原图像不同
	C.create(abs(A.rows - B.rows) + 1, abs(A.cols - B.cols) + 1, A.type());
	//计算DFT变换的尺寸
	//为了提升傅立叶变换的速度,用函数对待处理的图像进行size的扩充
	Size dftsize;
	dftsize.width = getOptimalDFTSize(A.cols + B.cols - 1);
	dftsize.height = getOptimalDFTSize(B.rows + A.rows - 1);
	//分配临时缓冲区并初始化置零
	//创造出扩充之后的“工具”矩阵
	Mat tempA(dftsize, A.type(), Scalar::all(0));
	Mat tempB(dftsize, B.type(), Scalar::all(0));
	//复制A和B到tempA和tempB的左上角
	//此时对“工具”矩阵进行傅立叶变换时,左上角的部分已经是待处理图像的真复制
	//相当于对原图像进行了“快速的”傅立叶变换
	Mat roiA(tempA, Rect(0, 0, A.cols, A.rows));
	Mat roiB(tempB, Rect(0, 0, B.cols, B.rows));
	A.copyTo(roiA);
	B.copyTo(roiB);
	//进行快速傅立叶变换,并将nonzeroRow参数置为非零,以进行更快的处理
	//第三个参数是标识符,设为0就是正经的傅立叶变换
	//第四个参数是用于加快运算速度,认为前A.rows行是非零行,需要计算,后面为0行,不需要计算
	//这就省去了扩充图像中无效部分的计算
	dft(tempA, tempA, 0, A.rows);
	dft(tempB, tempB, 0, B.rows);
	//得到的频谱相乘,结果存放在tempA中
	//第一第二参数为相乘复数矩阵,三为输出矩阵,四为输出形式(复数or实部)
	mulSpectrums(tempA,tempB,tempA, DFT_REAL_OUTPUT);
	//将结果变换为频域,采用nonzeroRow==C.rows
	//这里标识符取INVERSE+SCALE,前者表示逆变换,后者表示结果“/N”,因为这里傅立叶变换的结果是公式中的后半部分
	//nonzeroRows取c.rows同理是为了不影响源图像的情况下,加快运算速度
	dft(tempA, tempA, DFT_INVERSE + DFT_SCALE, C.rows);
	//结果复制到C中
	//只需要复制roi所在的部分,有效信息
	tempA(Rect(0, 0, C.cols, C.rows)).copyTo(C);

}


int main()
{
	
	Mat assassin = imread("E:\\material\\assassin.jpeg", 0);
	if (assassin.empty())
		return -1;

	Mat kernel = (Mat_<float>(3, 3) << -1, -1, -1, -1, 9, -1, -1, -1, -1);
	cout << "按q终止演示" << endl;

	Mat floatI = Mat_<float>(assassin);   
	Mat filteredI;
	convolveDFT(floatI, kernel, filteredI); //注意傅立叶变换的对象必须是浮点型,不能是整型

	normalize(filteredI, filteredI, 0, 1, NORM_MINMAX); // 对所得对象进行归一化操作,以使得能映射到像素空间
											
	imshow("image", assassin);
	imshow("filtered", filteredI);  //当图像为浮点型的时候,在0~1内输出图像,相当于int 0~255在0~1的映射
	while((char)waitKey(0)!='q');

}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值