离散傅里叶变换
原文:http://blog.sina.com.cn/s/blog_154bd48ae0102wd8q.html
小知识:实部与虚部
实部和虚部分别指的是正余弦信号前面的系数
其实傅里叶变换本没有实部虚部的特殊含义,因为这个过程中所有的输入输出量都是看做复数的。就好像我们在做实数计算时,一般不会考虑结果的个位与十位有什么特殊含义一样。
不过,考虑到对图像变换时,输入信号是纯实数,按照傅里叶变换的性质,有:输入信号中的偶对称分量变换为实部,奇对称分量变换为虚部。
matlab画出自己的实部和虚部
clc; clear;
n=1:100;
x=10*exp((-0.1+0.2j*pi).*n)
plot(n,real(x)); % x的实部
title('real part of x');
figure;
plot(n,imag(x)); % x的虚部
title('imaginary part of x');
离散傅里叶变换是指傅里叶变换在时域和频域上都呈现出离散的形式,将时域信号的采样变换成为在离散时间傅里叶变换频域的采样。
简单来说,对一张图像使用傅里叶变换就是将它分解成正弦和余弦两部分,也就是将图像从空间域转换到频域。在频域里,高频部分代表了图像的细节、纹理信息,而低频部分代表了图像的轮廓信息。
傅里叶变换在图像处理中的应用:图像的增强与图像去噪、图像分割之边缘检测、图像特征提取、图像压缩
下面来列出本节要学习的函数清单
1.dft()傅里叶变换
2.getOptimalDFTSize()返回DFT的最佳尺寸
3.copyMakeBorder()扩充图像边界
4.Magnitude()计算二维矢量的幅值
5.Log()计算自然对数
6.Normalize()矩阵归一化
1.void dft(InputArray src,OutputArray dst ,int flags=0,int nonzeroRows=0)
第一个参数:输入图像
第二个参数:输出图像,前两个参数我们已经很熟悉了
第三个参数:转换的标识符,默认值为0,此时默认的应该是正向变换,还有很多其他的标识符,比如DFT_INVERSE(用一维或者二维逆变换代替默认的正向变换)
第四个参数:默认值为0,如果此参数设为非0时(最好是取值为想要处理的那一行的值,比如C.rows),函数可以进行更高效的处理,节省时间开销。
2.Int getOptimalDFTSize(int vecsize)
此函数唯一的一个参数表示的是向量尺寸,为了提高离散傅里叶变换的运行速度,需要扩充图像,而具体扩充多少,由这个函数来计算得到
3.Void copyMakeBorder(InputArray src,OutputArray dst ,int top,int bottom,int left,int right,int borderType,const Scalar&value=Scalar())
第一个参数:输入图像
第二个参数:输出图像
第3-6个参数:分别表示在源图像的上下左右四个方向上扩充多少个像素
第七个参数:边界类型,常取值为BORDER_CONSTANT
第八个参数:扩充部分的像素值
4.Void magnitude(InputArray x,InputArray y,OutputArray magnitude)
第一个参数:表示矢量的浮点型X的坐标值,也就是实部
第二个参数:表示矢量的浮点型Y的坐标值,也就是虚部
第三个参数:输出的幅值,和第一个参数X有着同样的尺寸和类型
5.Void log(InputArray src,OutputArray dst)
第一个参数为输入的源图像
第二个参数为输出的对数值
6.Void normalize(InputArray src,OutputArray dst,double alpha=1,double bata=0,int norm_type=NORM_L2,int dtype=-1,InputArraymask=noArray())
第一个参数:输入图像
第二个参数:输出图像
第三个参数:归一化后的最大值,默认为1
第四个参数:归一化后的最小值,默认为0
第五个参数:归一化类型,默认NORM_L2
第六个参数:默认值-1,当此参数取负值时,输出矩阵和src有同样的类型,否则,它和src有同样的通道数,且此时图像深度为CV_MAT_DEPTH
第七个参数:可选的操作掩膜,有默认值noArray()
程序代码
//离散傅里叶变换的程序
#include"stdafx.h"
#include
using namespace cv;
using namespace std;
int main()
{
//读入图像
Mat image = imread("E:\\222.jpg",0);
imshow("原图", image);
//扩展图像的像素
int m = getOptimalDFTSize(image.rows);
int n = getOptimalDFTSize(image.cols);
Mat image1;
copyMakeBorder(image, image1, 0, m-image.rows, 0, n-image.cols,BORDER_CONSTANT, Scalar::all(0));
//为虚数部分分配空间,image2是一个二维的向量,一个内容是image1的复制,一个内容全为0
Mat image2[] = {Mat_<</span>float>(image1),Mat::zeros(image1.size(),CV_32F)};
Mat complex1;
merge(image2, 2, complex1);
//进行就地傅里叶运算
dft(complex1,complex1);
//进行幅度运算
split(complex1, image2);
magnitude(image2[0],image2[1],image2[0]);
Mat magnitudeimage = image2[0];
//进行对数运算
magnitudeimage += Scalar::all(1);
log(magnitudeimage, magnitudeimage);
//进行剪切和重分部,对于重分部,是让四个顶点集中到中心这一点上,形成四个象限
magnitudeimage = magnitudeimage( Rect(0, 0, magnitudeimage.cols&-2, magnitudeimage.rows&-2));
int cx = magnitudeimage.cols / 2;
int dx = magnitudeimage.rows / 2;
Mat q0(magnitudeimage, Rect(0, 0, cx, dx));//右上角
Mat q1(magnitudeimage, Rect(cx, 0,cx,dx));
Mat q2(magnitudeimage, Rect(0, dx, cx, dx));
Mat q3(magnitudeimage, Rect(cx, dx, cx, dx));
Mat temp;
q0.copyTo(temp);
q3.copyTo(q0);
temp.copyTo(q3);
q1.copyTo(temp);
q2.copyTo(q1);
temp.copyTo(q2);
//归一化
normalize(magnitudeimage,magnitudeimage,1,0,CV_MINMAX);
imshow("频谱图", magnitudeimage);
waitKey();
return 1;
}
结果截图
下面分别示出几张不同的图像以及他的频域图像
疑问:我并不明白剪切的意义何在,为何要剪切为最大的偶数,而下图中左图是剪切了的,右图是未剪切(均未重分布),并未见有何区别,如果您读到这篇文章知道答案,可以留言告诉我,如果在后面的学习中慢慢理解,我也会在这里更新给大家。
文章来源: blog.csdn.net,作者:网奇,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/jacke121/article/details/54589020
- 点赞
- 收藏
- 关注作者
评论(0)