傅里叶变换
对一张图像运用傅立叶变换就是将它分解成正弦和余弦两部分,也就是将图像从空间域(spatial domain)转换到频域(frequency domain)。这是因为任一函数都可以表示成无数个正弦函数和余弦函数的和的形式。
二维傅里叶变换的表达式
getOptimalDFTSize():
DFT的运行速度与图像大小有关。当图像大小为2、3或5的倍数时,DFT运行速度最快,通过getOptimalDFTSize() 函数可以返回傅里叶变换所对应的最优尺寸大小。
int getOptimalDFTSize(int vecsize)
copyMakeBorder():
扩充图像边界。例如top=1, bottom=1, left=1, right=1 意味着在原图像的上下左右各扩充一个像素宽度的边界。
void copyMakeBorder(InputArray src, OutputArray dst,
int top, int bottom,int left, int right,
int borderType, const Scalar& value=Scalar() )
merge():合并多个单通道图像到一个多通道图像。
void merge(const Mat*mv, size_t count, OutputArray dst)
The following example shows how to merge 3 single channel matrices into a single 3-channel matrix.
Mat m1 = (Mat_<uchar>(2,2) << 1,4,7,10);
Mat m2 = (Mat_<uchar>(2,2) << 2,5,8,11);
Mat m3 = (Mat_<uchar>(2,2) << 3,6,9,12);
Mat channels[3] = {m1, m2, m3};
Mat m;
merge(channels, 3, m);
/*
m =
[ 1, 2, 3, 4, 5, 6;
7, 8, 9, 10, 11, 12]
m.channels() = 3
*/
magnitude():计算幅值
void magnitude(InputArray x, InputArray y, OutputArray magnitude)
dft():傅里叶变换
void dft(InputArraysrc, OutputArray dst, int flags=0, int nonzeroRows=0)
代码示例
#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgcodecs.hpp"
#include <iostream>
using namespace cv;
using namespace std;
int main(int argc, char ** argv)
{
const char* filename = "../data/lena.jpg";
Mat I = imread(filename, IMREAD_GRAYSCALE);
if (I.empty())
{
cout << "Error opening image" << endl;
return -1;
}
Mat padded;
int m = getOptimalDFTSize(I.rows); // DFT最优行数
int n = getOptimalDFTSize(I.cols); // DFT最优列数
copyMakeBorder(I, padded, 0, m - I.rows, 0, n - I.cols, BORDER_CONSTANT, Scalar::all(0)); //扩展原图像边界到padded
Mat planes[] = { Mat_<float>(padded),Mat::zeros(padded.size(),CV_32F) }; // 第一个实数矩阵,第二个构造复数矩阵
Mat complexI; // 复数矩阵
merge(planes, 2, complexI); // 合并两个矩阵到complexI
dft(complexI, complexI); // 傅里叶变换
split(complexI, planes); // planes[0] = Re(DFT(I), planes[1] = Im(DFT(I))
magnitude(planes[0], planes[1],planes[0]); // 前两个参数输入,第三个参数输出幅值
Mat magI = planes[0]; // 幅值
magI += Scalar::all(1);
log(magI, magI); // 第一个输入,第二个输出,M1 = log(1+M)
magI = magI(Rect(0, 0, magI.cols & -2, magI.rows & -2)); // Rect_成员变量x、y、width、height
// -2补码11111110,若有奇数行或列则裁剪
int cx = magI.cols / 2;
int cy = magI.rows / 2;
Mat q0(magI, Rect(0, 0, cx, cy)); // 左上
Mat q1(magI, Rect(cx, 0, cx, cy)); // 右上
Mat q2(magI, Rect(0, cy, cx, cy)); // 左下
Mat q3(magI, Rect(cx, cy, cx, cy)); // 右下
Mat tmp; // 中心化
q0.copyTo(tmp);
q3.copyTo(q0);
tmp.copyTo(q3);
q1.copyTo(tmp);
q2.copyTo(q1);
tmp.copyTo(q2);
normalize(magI, magI, 0, 1, NORM_MINMAX); // 归一化至区间[0,1]
imshow("Input Image", I);
imshow("spectrum magnitude", magI);
waitKey();
return 0;
}
运行结果