赞
踩
目录
离散傅里叶变换(DFT)基础知识理解参考:
FFTW库基本使用参考:
关于FFTW库的使用和离散傅里叶变换的基础知识参考上述两篇优秀文章即可,我学习过程中也是参考上述文章进行学习的,此文着重于二维傅里叶变换方面FFTW库在实践过程中的问题及解决。
二维傅里叶变换:将1个图像分解为若干复平面波之和,将图像从空间域转至频域
平面波:在一个方向上存在一个正弦函数,在法线方向上将其拉伸(正弦平面波)
表示平面波所需参数: 平面波举例:
二维傅里叶变换过程图示:
将输入图像分解为若干平面波之和,图像每个点像素由RGB组成,FFTW输入计算时,需将RGB变为灰度值
平面波合成图解:
输出结果一半在分析前需进行频谱中心化,这样讲有助于分析,下面将分别记录。
频谱中心化:将4个区域的顺序对调(14对调 23对调),从而使输出低频在中心,高频在四周,这样有助于分析,更符合人们观察习惯。频谱中心化后,中心低频就是直流。建议第二种方法,第一种方法中心不确定,易出错
频谱中心化对各平面波幅度,相位,频率,方向均无影响,此时方向为矩阵中心指向元素所在位置,无影响。
注意:频谱中心化对输出数据的顺序进行了修改,若需要进行逆变换,则需再次进行一次频谱中心化操作,使数据恢复原始状态,否则逆变换结果有误。
频谱图:计算中心化后各点的幅值,对幅值进行归一化,将其大小控制在0-255之间,并以此值作为灰度值,绘制灰度图。
归一化目的:灰度图各点数值范围为0-255,而输出各点幅值数据大小并非在此范围中,即使全部在此范围中,也并非均匀分布,上述情况均会使成图效果低下,导致全黑或全白或其他情况。归一化后将数值范围限制在0-255中,并将数值按大小比例分布在范围内,成图效果好。
效果如下:(绘图使用Opencv)
原图: 中心化归一化频谱图:
未中心化归一化频谱图: 中心化未归一化频谱图:
以下几种情况会导致绘图结果不同:
二维傅里叶逆变换:将图像由频域转为空间域,即将各平面波进行合成,从而形成图像
效果如下:
原图: 逆变换:
原图: 逆变换:
原图为RGB三色图,但由于在正向变换前将图片变为了灰度图,导致逆变换后的结果仍为灰度图,若想要对RGB图像变换而非灰度图,则对R,G,B三通道数值单独进行正变换,再依次逆变换后,将得到的三组数据合成RGB三色数据,即可得到原始三色图
逆变换注意:
二维傅里叶变换的结果中每一个点代表一种平面波,每对关于中心对称的一对数值点,经过逆变换后,可得到相应平面波。
中心:输出结果的中心不一定在矩阵中心
如:(5,5)的矩阵中心为(3,3),但FFTW中二维傅里叶输出结果的中心可能在(3,4)(4,4)等(5,5)附近的点上(可能是小数),判断中心点需比较对角数据,从而计算出中心点的具体所在位置,若中心点找错,即导致所选的两对频点并不对称,逆变换的结果也就是错误的
对称频点:实部相同,虚部互为相反数
例:
原图:大小(318*318)(0-317)
下图对应数据分别为左上角和右下角中5*5大小的输出结果
图中紫色部分数据相同,即(1,1)与(317,317)相同,而不是(0,0)与(317,317)相同,第0列和第0行无对称点
即对称点为(159,159),且第0列和第0行无对称点
成图流程:
效果如下:
!若所选取的频点对应频率过高,会导致一个像素内多次数据重复,从而使结果无法正确显示!
流程:
1.求出各点幅值
2.对各点幅值加一并进行1og运算,减小范围(缩小数据分布间隔,使分布更均匀,成图效果更好)
3.求出2中最大值最小值之差,并用255除以其值得到步长scale
4.用最小值乘以步长得到偏差
5.各值乘以步长减去偏差即可
实现(使用Opencv):
- double min1 = 0.0, max1 = 0.0;
- minMaxLoc(backward, &min1, &max1);
- double scale1 = 255 / (max1 - min1);
- double shift1 = -min1 * scale1;
- Mat myImage1;
- convertScaleAbs(backward, myImage1, scale1, shift1);
-
- // 此代码未进行log过程,若有需要可添加
- // 相关函数为Opencv中相关函数
频谱中心化实现方法之前已经提及,此处给出实现:
互换区域中心化:
- void fftshift(Mat source, Mat& dest)
- {
- int row = source.rows;
- int col = source.cols;
- int halfRow = row / 2;
- int halfCol = col / 2;
- int temp = 0;
-
- for (size_t j = 0; j < row; j++)
- {
- temp = (j + halfRow) % row;
- for (size_t i = 0; i < col; i++)
- {
- *dest.ptr<float>(temp, i) = *source.ptr<float>(j, i);
- }
- }
-
- source = dest.clone();
-
- for (size_t i = 0; i < col; i++)
- {
- temp = (i + halfCol) % col;
- for (size_t j = 0; j < row; j++)
- {
- *dest.ptr<float>(j, temp) = *source.ptr<float>(j, i);
- }
- }
-
- }
输入乘以 (建议):
- void fftshift2(Mat source, Mat& dest)
- {
- int row = source.rows;
- int col = source.cols;
- int halfRow = row / 2;
- int halfCol = col / 2;
-
- for (int j = 0; j < col; j++)
- {
- for (int i = 0; i < row; i++)
- {
- *dest.ptr<float>(i, j) = *source.ptr<float>(i, j) * (pow(-1, i + j));
- }
- }
- }
将R,G,B各单通道数据拿出分别进行变换,逆变换也是分别进行,最后再将各单通道数据组合
效果如下:
原图: B通道正变换:
G通道正变换: R通道正变换:
B通道逆变换: G通道逆变换:
R通道逆变换: (B,G,R)逆变换组合:
1.二维图像输入应使用二维数组,但fftw中二维输入仍以一维数组方式存储,在调用方法时,指定二维输入的行列,以便于分割
2.复数类型中实数输入需转变为复数,虚部为0
3.空间申请需使用fftw内部给定的类型,防止内存出现错误
4.方法的创建放在输入赋值之前
5.使用fftw_destroy_plan和fftw_free释放方法和输入输出数据所占的空间
6.同一方法在不修改输入输出大小的前提下,可更改内部数据重复多次变换。
1.Fftw中所有rtc/ctr函数将正逆变换分开,输入是n个实数,而输出是n/2+1 个复数,输出只有n/2+1位,申请n空间,未初始化则n/2+1位后面则无数据,若未初始化则后面数据未知,因此应只为输出申请n/2+1空间或对n空间输出进行初始化即可(即所有rtc/ctr函数正变换输出只有n/2+1个数据有效)
分析时需注意所有rtc/ctr函数的正变换输出有效位数,切勿使用无效数据
2.非rtc/ctr函数的正变换n/2+1之后的数据为之前数据的对称,故使用此方法时可分析全部数据
3.所有rtc/ctr函数生成方法时仍需指定完整长度数值
未初始化:
初始化0:
初始化1:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。