`

opencv之离散傅里叶变换

 
阅读更多

 

        距离进入实验室已经快1个月了,小编还没有把C++和opencv看完,嗯。。。和我之前计划的不一样,计划赶不上变化,人生无常,摸一把辛酸泪,还要继续努力啊!!!

        离别已久的周六组会又要来了,这次要拿下“离散傅里叶变化”。

 

        书上说,离散傅里叶变化(Discrete Fourier Transform,缩写为DFT),是指傅里叶变换在时域和频域上都呈现离散的形式,将时域信号的采样变换为在离散时域傅里叶变换(DTFT)频域的采样。

        书上说的很抽象,很复杂,小编去搜了搜时域(spatial domain)和频域(frequency domain)。首先,时域和频域是信号的基本性质,这样可以用多种方式来分析信号,每种方式提供了不同的角度。解决问题的最快方式不一定是最明显的方式,用来分析信号的不同角度称为域。时域是真实世界,是惟一实际存在的域。因为我们的经历都是在时域中发展和验证的,已经习惯于事件按时间的先后顺序地发生。频域,尤其在射频和通信系统中运用较多,在高速数字应用中也会遇到频域。频域最重要的性质是:它不是真实的,而是一个数学构造。时域是惟一客观存在的域,而频域是一个遵循特定规则的数学范畴,频域也被一些学者称为上帝视角。

        如下图所示,上面是时域,下面是频域。

        那么,是什么傅里叶变换呢?

        傅里叶变换是一种线性的积分变换。它就是一种变换。对一张图像使用傅里叶变换就是将他分解成正弦和余弦两个部分,也就是将图像从空间域转换到频域。傅里叶变换就是一个用来将函数分解的工具。

        傅里叶变换分为四种:连续傅里叶变换、傅里叶级数、离散时域傅里叶和离散傅里叶。这里就说一下离散傅里叶吧。

        二维图像的傅里叶变换可以用以下数学公式表达。

        式中f是空间域值,F是频域值。好吧,数学公式其实我也看不懂,没关系,不影响理解。

        转换之后的频域值是复数,因此,显示傅里叶变换之后的结果需要用实数图像(real image)加虚数图像(complex image),或者幅度图像(magitude image)加相位图像(phase image)的形式。

        幅度图像:表示振幅的图像。相位图像:相位是对于一个波,特定的时刻在它循环中的位置(一种它是否在波峰、波谷或者他们之间的某点的标度)。

        在实际的图像处理的过程中,仅仅使用了幅度图像,因为幅度图像包含了原图像的几乎所有我们需要的几何信息。然而,如果想要通过修改幅度图像或者相位图像的方法来间接修改原空间图像,需要使用逆傅里叶变换得到修改后的空间图像,这样就必须同时保留幅度图像和相位图像。

 

        如果需要得到图像中的几何结构信息,那就需要傅里叶变换。在频域里面,对于一幅图像,高频部分代表了图像的细节、纹理信息;低频部分代表了图像的轮廓信息。如果对一副精细的图像使用低通滤波器,那么滤波后的结果就只剩下轮廓了。如果图像受到的噪声恰好位于某个特定的“频率”范围内,则可以通过滤波器来恢复原来的图像。

        傅里叶变换在图像处理中可以做到图像增强与图像去噪、图像分割之边缘检测、图像特征提取、图像压缩等。

        傅里叶变换的意义:

        为什么我们要用正弦曲线来代替原来的曲线呢?如果我们如果我们也还可以用方波或三角波来代替,分解信号的方法是无穷的,但分解信号的目的是为了更加简单地处理原来的信号。用正余弦来表示原信号会更加简单,因为正余弦拥有其他信号所不具备的性质:正弦曲线保真度。一个正弦曲线信号输入后,输出的仍是正弦曲线,只有幅度和相位可能发生变化,但是频率和波的形状仍是一样的,且只有正弦曲线才拥有这样的性质,正因如此我们才不用方波或三角波来表示。

        傅立叶变换的物理意义在哪里?

        立叶原理表明:任何连续测量的时序或信号,都可以表示为不同频率的正弦波信号的无限叠加。而根据该原理创立的傅立叶变换算法利用直接测量到的原始信号,以累加方式来计算该信号中不同正弦波信号的频率、振幅和相位。当然这是从数学的角度去看傅立叶变换。

        那么从物理的角度去看待傅立叶变换,它其实是帮助我们改变传统的时间域分析信号的方法转到从频率域分析问题的思维。

        所以,最前面的时域信号在经过傅立叶变换的分解之后,变为了不同正弦波信号的叠加,我们再去分析这些正弦波的频率,可以将一个信号变换到频域。有些信号在时域上是很难看出什么特征的,但是如果变换到频域之后,就很容易看出特征了。

        傅立叶变换提供给我们这种换一个角度看问题的工具,看问题的角度不同了,问题也许就迎刃而解!

//用dft函数计算两个二维实矩阵卷积,参照opencv3编程入门
void convolveDFT(InputArray A, InputArray B, OutputArray C)
//InputArray和OutputArray两个类都是代理数据类型,可以看做一个接口。
//InputArrayMat、Mat_<T>、Mat_<T, m, n>、vector<T>、
//vector<vector<T>>、vector<Mat>。

{
	//[1]初始化输出矩阵
	C.create(abs(A.rows - b.rows) + 1, abs(A.cols - B.cols) + 1, A.type());
	//输出的C调用create函数(行,列,类型)创建矩阵
	//abs()函数求绝对值

	Size dftSize;
	//Size类设置大小

	//[2]计算DFT变换的尺寸
	dftSize.width = getOptimalDFTSize(A.cols + B.cols - 1);
	dftSize.height = getOptimalDFTSize(A.rows + B.rows - 1);
	//getOptimalDFTSize函数返回DFT最优尺寸大小。

	//[3]分配临时缓冲区并初始化置0
	Mat tempA(dftSize, A.type(), Scalar::all(0));
	Mat tempB(dftSize, B.type(), Scalar::all(0));
	//Scalar()对矩阵初始化赋值。它有一个单独的成员val,它是一个指向4个双精度浮点数数组的指针
	//ScalarAll(),一个参数,并且val[]中的4个元素都是这个参数
	//RealScalar(),一个参数,它被传递给val[0],而val[]数组别的值被赋为0
	//Scalar(),需要一个、两个、三个或者四个参数并将这些参数传递给数组val[]中的相应元素

	//[4]分别复制A和B到tempA和tempB的左上角
	Mat roiA(tempA, Rect(0, 0, A.cols, A.cows));
	A.copyTo(roiA);
	Mat roiB(tempB, Rect(0, 0, B.cols, B.cows));
	B.copyTo(roiB);

	//[5]就地操作(in-place),进行快速傅里叶变换,并将nonzeroRows参数设置为非0,以进行更加快速的处理
	dft(tempA, tempA, 0, A.rows);
	dft(tempB, tempB, 0, B.rows);

	//[6]将得到的频谱相乘,结果存放到tempA中
	mulSpectrums(tempA, tempB, tempA);
	//傅里叶频谱的乘法mulApectrums,前两个参数相乘,放到第三个参数中

	//[7]将结果变换为频域,且尽管结果行(result rows)都为非零,我们只需要其中的C.rows的第一行,所以采用nonzeroRows==C.rows
	dft(tempA, tempA, DFT_INVERSE + DFT_SCALE, C.rows);

	//[8]将结果复制到C中
	tempA(Rect(0, 0, C.cols, C.rows).copyTo(C));

	//[9]所有的临时缓冲区将被自动释放,所以无需收尾操作
}

 

  • 大小: 58 KB
  • 大小: 32.2 KB
  • 大小: 173.8 KB
分享到:
评论
发表评论

文章已被作者锁定,不允许评论。

相关推荐

Global site tag (gtag.js) - Google Analytics