Opencv学习笔记 离散傅里叶变换(DFT)

    科技2022-07-10  162

            离散傅里叶变换(Discrete Fourier Transform,缩写为DFT),是傅里叶变换在时域和频域上都呈离散的形式,将信号的时域采样变换为其DTFT的频域采样。在形式上,变换两端(时域和频域上)的序列是有限长的,而实际上这两组序列都应当被认为是离散周期信号的主值序列。即使对有限长的离散信号作DFT,也应当将其看作其周期延拓的变换。在实际应用中通常采用快速傅里叶变换计算DFT。        

            快速傅里叶变换 (fast Fourier transform), 即利用计算机计算离散傅里叶变换(DFT)的高效、快速计算方法的统称,简称FFT。快速傅里叶变换是1965年由J.W.库利和T.W.图基提出的。采用这种算法能使计算机计算离散傅里叶变换所需要的乘法次数大为减少,特别是被变换的抽样点数N越多,FFT算法计算量的节省就越显著。

            代码如下:

    string filename = @"C:\\Users\\Desktop\\imageTextN.png"; // string filename = "imageTextR.png"; Mat image = Cv2.ImRead(filename, ImreadModes.Grayscale); Mat imageCopy = image.Clone(); // 将输入图像扩大到最佳尺寸 Mat padded = new Mat(); int m = Cv2.GetOptimalDFTSize(image.Rows); int n = Cv2.GetOptimalDFTSize(image.Cols); Cv2.CopyMakeBorder(image, padded, 0, m - image.Rows, 0, n - image.Cols, BorderTypes.Constant, Scalar.All(0)); Mat temp = new Mat(); padded.ConvertTo(temp, MatType.CV_32F); Mat[] planes = new Mat[]{ temp, Mat.Zeros(padded.Size(), MatType.CV_32F) }; Mat complexImage = new Mat(); // 吧一个zeros通道和扩展通道合并在一起 Cv2.Merge(planes, complexImage); // dft是一个in-place操作 Cv2.Dft(complexImage, complexImage); // 将DFT实数和虚数部分变换成幅值 Cv2.Split(complexImage, out planes);// planes[0]为DFT变换结果的实部,planes[1]为虚部 Cv2.Magnitude(planes[0], planes[1], planes[0]);// 如此planes[0]存储的幅值大小 Mat magImage = planes[0]; // 将幅值转换到对数空间 magImage += Scalar.All(1); Cv2.Log(magImage, magImage); // 如果图像的尺寸是奇数的话对图像进行裁剪并重新排列 magImage = new Mat(magImage, new Rect(0, 0, magImage.Cols & -2, magImage.Rows & -2)); // 重新排列Fourier图像的象限,使得图像的中心在象限的原点 int cx = magImage.Cols / 2; int cy = magImage.Rows / 2; Mat q0 = new Mat(magImage, new Rect(0,0,cx,cy)); // 左上 Mat q1 = new Mat(magImage, new Rect(cx, 0, cx, cy)); // 右上 Mat q2 = new Mat(magImage, new Rect(0, cy, cx, cy)); // 左下 Mat q3 = new Mat(magImage, new Rect(cx, cy, cx, cy)); // 右下 Mat tmp = new Mat(); //交换象限 (左上与右下交换) q0.CopyTo(tmp); q3.CopyTo(q0); tmp.CopyTo(q3); //交换象限 (右上与左下) q1.CopyTo(tmp); q2.CopyTo(q1); tmp.CopyTo(q2); // 将幅度矩阵转化为0~1之间的浮点型数据方便显示 Cv2.Normalize(magImage, magImage, 0, 1, NormTypes.MinMax); Cv2.ImShow("input image", image); // 将32fc1的图片转为,8UC1, 0-1重新映射到0-255,为了显示 Mat temp1 = new Mat(); magImage.ConvertTo(temp1, MatType.CV_8UC1, 255); Cv2.ImShow("spectrum magnitude", temp1);

            Fourier变换的用处十分广泛,比如我们可以用来检验图像中的几何朝向信息。例如图片中的文字,本行也以水平线的形式出现,字母则以垂直线的形式出现,在傅立叶变换下,也可以看到文本片段的这两个主要组成部分:

     

            水平方向

     

            文字旋转

            从Fourier变换的频域图像上可以看出频域中最具影响力的部分(幅度图像上最亮的点)跟随图像上对象的几何旋转, 据此,我们可以计算偏移量并执行图像旋转以校正图像。

            参考资料:

            https://shawnzhang31.com/topic/opencvtutorial/CoreModule/DiscreteFourierTransform/DiscreteFourierTransform.html

            https://zhuanlan.zhihu.com/p/149528521

    Processed: 0.133, SQL: 8