首页 > 编程语言 > 详细

20210112 OpenCV傅立叶变换(C++)

时间:2021-01-12 23:56:45      阅读:49      评论:0      收藏:0      [点我收藏+]

1. 理论基础

1.1 第一类间断点和第二类间断点

如果x0是函数f(x)的间断点,且左极限和右极限都存在,则x0是f(x)的第一类间断点。左右极限相等为可去间断点,否则为跳跃间断点;

非第一类间断点称为第二类间断点。

1.2 狄利克雷(Dirichlet)充分条件

在一个周期内连续或只有有限个第一类间断点;在一个周期内至多只有有限个极值点;函数可积。

1.3 傅立叶变换

如果t满足狄利克雷条件

技术分享图片       1式

技术分享图片 2式

 

1式称为f(t)的傅立叶变换

2式称为F(amiga)的傅立叶逆运算

2. 代码实战

#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

using namespace cv; using namespace std; int main() { // 读入灰度图 // 0代表灰度,1代表3通道bgr Mat srcImage = imread("/Users/xxx/data/image_folder/玫瑰花.jpg", 0); cout << srcImage.size() << endl; // 将输入图像扩展到最佳尺寸,边界用0填充 // 离散傅里叶变换的运行速度与图像的大小有很大的关系,当图像的尺寸使2,3,5的整数倍时,计算速度最快 // 为了达到快速计算的目的,经常通过添加新的边缘像素的方法获取最佳图像尺寸 // 函数getOptimalDFTSize()用于返回最佳尺寸,copyMakeBorder()用于填充边缘像素 int m = getOptimalDFTSize(srcImage.rows); int n = getOptimalDFTSize(srcImage.cols); Mat padded; copyMakeBorder(srcImage, padded, 0, m - srcImage.rows, 0, n - srcImage.cols, BORDER_CONSTANT, Scalar::all(0)); cout << padded.size() << padded.channels() << endl; // 为傅立叶变换的结果分配存储空间 // 将plannes数组组合成一个多通道的数组,两个同搭配,分别保存实部和虚部 // 傅里叶变换的结果使复数,这就是说对于每个图像原像素值,会有两个图像值 // 此外,频域值范围远远超过图象值范围,因此至少将频域储存在float中 // 所以我们将输入图像转换成浮点型,并且多加一个额外通道来存储复数部分 Mat planes[] = {Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F)}; Mat complexI; merge(planes, 2, complexI); cout << complexI.size() << endl; cout << planes->size() << endl; // 进行离散傅立叶变换 dft(complexI, complexI); // 将复数转化为幅值,保存在planes[0] split(complexI, planes); // 将多通道分为几个单通道 magnitude(planes[0], planes[1], planes[0]); Mat magnitudeImage = planes[0]; // 傅里叶变换的幅值达到不适合在屏幕上显示,因此我们用对数尺度来替换线性尺度 // 进行对数尺度logarithmic scale缩放 magnitudeImage += Scalar::all(1); // 所有的像素都加1 log(magnitudeImage, magnitudeImage); // 求自然对数 // 剪切和重分布幅度图像限 // 如果有奇数行或奇数列,进行频谱裁剪 magnitudeImage = magnitudeImage(Rect(0, 0, magnitudeImage.cols & -2, magnitudeImage.rows & -2)); // ---- -------- 下面的是为了显示结果 --------------- // 一分为四,左上与右下交换,右上与左下交换 // 重新排列傅里叶图像中的象限,使原点位于图像中心 int cx = magnitudeImage.cols / 2; int cy = magnitudeImage.rows / 2; Mat q0(magnitudeImage, Rect(0, 0, cx, cy)); // ROI区域的左上 Mat q1(magnitudeImage, Rect(cx, 0, cx, cy)); // ROI区域的右上 Mat q2(magnitudeImage, Rect(0, cy, cx, cy)); // ROI区域的左下 Mat q3(magnitudeImage, Rect(cx, cy, cx, cy)); // ROI区域的右下 //交换象限(左上与右下进行交换) Mat tmp; q0.copyTo(tmp); q3.copyTo(q0); tmp.copyTo(q3); //交换象限(右上与左下进行交换) q1.copyTo(tmp); q2.copyTo(q1); tmp.copyTo(q2); // 归一化 normalize(magnitudeImage, magnitudeImage, 0, 1, NORM_MINMAX); //【9】显示效果图 imshow("频谱幅值", magnitudeImage); waitKey(); return 0; }

 

20210112 OpenCV傅立叶变换(C++)

原文:https://www.cnblogs.com/jdbc2nju/p/14269907.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!