#include<opencv2/core/core.hpp> #include<opencv2/highgui/highgui.hpp> #include<opencv2/imgproc/imgproc.hpp> using namespace std; using namespace cv; Mat I;//输入的图像矩阵 Mat F;//图像的快速傅里叶变换 Point maxLoc;//傅里叶谱的最大值的坐标 int radius = 20;//截断频率 const int Max_RADIUS = 100;//设置最大的截断频率 Mat lpFilter;//低通滤波器 int lpType = 0;//低通滤波器的类型 const int MAX_LPTYPE = 2; Mat F_lpFilter;//低通傅里叶变换 Mat FlpSpectrum;//低通傅里叶变换的傅里叶谱灰度级 Mat result;//低通滤波后的效果 string lpFilterspectrum = "低通傅里叶谱";//显示窗口的名称 //快速傅里叶变换 void fft2Image(InputArray _src, OutputArray _dst); //幅度谱 void amplitudeSpectrum(InputArray _srcFFT, OutputArray _dstSpectrum) { //判断傅里叶变换是两个通道 CV_Assert(_srcFFT.channels() == 2); //分离通道 vector<Mat> FFT2Channel; split(_srcFFT, FFT2Channel); //计算傅里叶变换的幅度谱 sqrt(pow(R,2)+pow(I,2)) magnitude(FFT2Channel[0], FFT2Channel[1], _dstSpectrum); } //幅度谱的灰度级显示 Mat graySpectrum(Mat spectrum) { Mat dst; log(spectrum + 1, dst); //归一化 normalize(dst, dst, 0, 1, NORM_MINMAX); //为了进行灰度级显示,做类型转换 dst.convertTo(dst, CV_8UC1, 255, 0); return dst; } void callback_lpFilter(int, void*); /* 低通滤波的类型: (理想低通滤波器,巴特沃斯低通滤波器,高斯低通滤波器) */ enum LPFILTER_TYPE { ILP_FILTER = 0, BLP_FILTER = 1, GLP_FILTER = 2 }; //构建低通滤波器 Mat createLPFilter(Size size, Point center, float radius, int type, int n = 2); int main(int argc, char*argv[]) { /* -- 第一步:读入图像矩阵 -- */ I = imread(argv[1], CV_LOAD_IMAGE_GRAYSCALE); if (!I.data) return -1; imwrite("I1.jpg", I); //数据类型转换,转换为 浮点型 Mat fI; I.convertTo(fI, CV_32FC1, 1.0, 0.0); /* -- 第二步:每一个数乘以(-1)^(r+c) -- */ for (int r = 0; r < fI.rows; r++) { for (int c = 0; c < fI.cols; c++) { if ((r + c) % 2) fI.at<float>(r, c) *= -1; } } /* -- 第三、四步:补零和快速傅里叶变换 -- */ fft2Image(fI, F); //傅里叶谱 Mat amplSpec; amplitudeSpectrum(F, amplSpec); //傅里叶谱的灰度级显示 Mat spectrum = graySpectrum(amplSpec); imshow("原傅里叶谱的灰度级显示", spectrum); imwrite("spectrum.jpg", spectrum); //找到傅里叶谱的最大值的坐标 minMaxLoc(spectrum, NULL, NULL, NULL, &maxLoc); /* -- 低通滤波 -- */ namedWindow(lpFilterspectrum, WINDOW_AUTOSIZE); createTrackbar("低通类型:", lpFilterspectrum, &lpType, MAX_LPTYPE, callback_lpFilter); createTrackbar("半径:", lpFilterspectrum, &radius, Max_RADIUS, callback_lpFilter); callback_lpFilter(0, 0); waitKey(0); return 0; } void fft2Image(InputArray _src, OutputArray _dst) { //得到Mat类型 Mat src = _src.getMat(); //判断位深 CV_Assert(src.type() == CV_32FC1 || src.type() == CV_64FC1); CV_Assert(src.channels() == 1 || src.channels() == 2); int rows = src.rows; int cols = src.cols; //为了进行快速的傅里叶变换,我们经行和列的扩充,找到最合适扩充值 Mat padded; int rPadded = getOptimalDFTSize(rows); int cPadded = getOptimalDFTSize(cols); //进行边缘扩充,扩充值为零 copyMakeBorder(src, padded, 0, rPadded - rows, 0, cPadded - cols, BORDER_CONSTANT, Scalar::all(0)); //快速的傅里叶变换(双通道:用于存储实部 和 虚部) dft(padded, _dst, DFT_COMPLEX_OUTPUT); } //回调函数:调整低通滤波的类型,及截断频率 void callback_lpFilter(int, void*) { /* -- 第五步:构造低通滤波器 -- */ lpFilter = createLPFilter(F.size(), maxLoc, radius, lpType, 2); /*-- 第六步:低通滤波器和图像快速傅里叶变换点乘 --*/ F_lpFilter.create(F.size(), F.type()); for (int r = 0; r < F_lpFilter.rows; r++) { for (int c = 0; c < F_lpFilter.cols; c++) { //分别取出当前位置的快速傅里叶变换和理想低通滤波器的值 Vec2f F_rc = F.at<Vec2f>(r, c); float lpFilter_rc = lpFilter.at<float>(r, c); //低通滤波器和图像的快速傅里叶变换对应位置相乘 F_lpFilter.at<Vec2f>(r, c) = F_rc * lpFilter_rc; } } //低通傅里叶变换的傅里叶谱 amplitudeSpectrum(F_lpFilter, FlpSpectrum); //低通傅里叶谱的灰度级的显示 FlpSpectrum = graySpectrum(FlpSpectrum); imshow(lpFilterspectrum, FlpSpectrum); imwrite("FlpSpectrum.jpg", FlpSpectrum); /* -- 第七、八步:对低通傅里叶变换执行傅里叶逆变换,并只取实部 -- */ dft(F_lpFilter, result, DFT_SCALE + DFT_INVERSE + DFT_REAL_OUTPUT); /* -- 第九步:同乘以(-1)^(x+y) -- */ for (int r = 0; r < result.rows; r++) { for (int c = 0; c < result.cols; c++) { if ((r + c) % 2) result.at<float>(r, c) *= -1; } } //注意将结果转换 CV_8U 类型 result.convertTo(result, CV_8UC1, 1.0, 0); /* -- 第十步:截取左上部分,大小等于输入图像的大小 --*/ result = result(Rect(0, 0, I.cols, I.rows)).clone(); imshow("经过低通滤波后的图片", result); imwrite("lF.jpg", result); } //构造低通滤波器 Mat createLPFilter(Size size, Point center, float radius, int type, int n = 2) { Mat lpFilter = Mat::zeros(size, CV_32FC1); int rows = size.height; int cols = size.width; if (radius <= 0) return lpFilter; //构造理想低通滤波器 if (type == ILP_FILTER) { for (int r = 0; r < rows; r++) { for (int c = 0; c < cols; c++) { float norm2 = pow(abs(float(r - center.y)), 2) + pow(abs(float(c - center.x)), 2); if (sqrt(norm2) < radius) lpFilter.at<float>(r, c) = 1; else lpFilter.at<float>(r, c) = 0; } } } //构造巴特沃斯低通滤波器 if (type == BLP_FILTER) { for (int r = 0; r < rows; r++) { for (int c = 0; c < cols; c++) { lpFilter.at<float>(r, c) = float(1.0 / (1.0 + pow(sqrt(pow(r - center.y, 2.0) + pow(c - center.x, 2.0)) / radius, 2.0*n))); } } } //构造高斯低通滤波 if (type == GLP_FILTER) { for (int r = 0; r < rows; r++) { for (int c = 0; c < cols; c++) { lpFilter.at<float>(r, c) = float(exp(-(pow(c - center.x, 2.0) + pow(r - center.y, 2.0)) / (2 * pow(radius, 2.0)))); } } } return lpFilter; }