概述
前情提要
为啥我要在另一篇博客里已经详细写过DFT的情况下另起一篇单独介绍呢,这是因为我发现站内很多博客都没有对DFT的参数及输出值的一个点给出明确解释:就是在对某张图像进行傅立叶变换时需要对其进行通道扩充以满足变换后有实部虚部的需求,而在图像卷积时却直接对原图(单通道灰度)图进行傅立叶变换即可。
为了方便后人的查找,单独列出来供大家参考。
大纲
- dft参数介绍
- 示例代码
参数介绍
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');
}
最后
以上就是繁荣金毛为你收集整理的DFT参数介绍及在图像卷积中的应用的全部内容,希望文章能够帮你解决DFT参数介绍及在图像卷积中的应用所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复