#pragma #include <opencv2/opencv.hpp> #include <iostream> using namespace cv; using namespace std; //低通滤波的类型: enum LPFILTER_TYPE { ILP_FILTER = 0, BLP_FILTER = 1, GLP_FILTER = 2 }; namespace mycv { void Im_Contrast(cv::Mat src,cv::Mat &dst); cv::Mat createLPFilter(Size size, Point center, float radius, int type, int n); //1-理想低通滤波器,2-巴特沃斯低通滤波器,3-高斯低通滤波器 void fftFilter(cv::Mat srcImage,cv::Mat&dstImage,int rudus,int type); } //构造低通滤波器 cv::Mat mycv::createLPFilter(Size size, Point center, float radius, int type, int n) { 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; } void mycv::Im_Contrast(cv::Mat src, cv::Mat & dst) { int r = src.rows; int c = src.cols; double minValue; double maxValue; cv::Point minLocation; cv::Point maxLocation; cv::Point matchLocation; minMaxLoc(src, &minValue, &maxValue, &minLocation, &maxLocation, cv::Mat()); src.convertTo(dst, CV_32FC1); cv::Mat src_32fc = dst + 0.001; cv::log(src_32fc, src_32fc); float src_aver =exp(cv::sum(src_32fc)[0] / (r*c));//平均值 dst = (dst / src_aver + 1); cv::log(dst, dst); float m_denormitor; m_denormitor=cv::log(maxValue / src_aver + 1); dst = dst / m_denormitor; dst.convertTo(dst, CV_8UC1,255,0); } void mycv::fftFilter(cv::Mat srcImage, cv::Mat & dstImage, int radius, int type) { //数据类型转换,转换为 浮点型 Mat srcFc1; srcImage.convertTo(srcFc1, CV_32FC1, 1.0, 0.0); /* -- 第二步:每一个数乘以(-1)^(r+c) -- */ for (int r = 0; r < srcFc1.rows; r++) { for (int c = 0; c < srcImage.cols; c++) { if ((r + c) % 2) srcFc1.at<float>(r, c) *= -1; } } //【2】将输入图像延扩到最佳的尺寸,边界用0补充 int m = getOptimalDFTSize(srcImage.rows); int n = getOptimalDFTSize(srcImage.cols); //将添加的像素初始化为0. Mat padded; copyMakeBorder(srcFc1, padded, 0, m - srcImage.rows, 0, n - srcImage.cols, BORDER_CONSTANT, Scalar::all(0)); //【3】为傅立叶变换的结果(实部和虚部)分配存储空间。 //将planes数组组合合并成一个多通道的数组complexI Mat planes[] = { Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F) }; Mat complexI; merge(planes, 2, complexI); //【4】进行就地离散傅里叶变换 dft(complexI, complexI); //【5】将复数转换为幅值,即=> log(1 + sqrt(Re(DFT(I))^2 + Im(DFT(I))^2)) split(complexI, planes); // 将多通道数组complexI分离成几个单通道数组,planes[0] = Re(DFT(I), planes[1] = Im(DFTI)) magnitude(planes[0], planes[1], planes[0]);// planes[0] = magnitude Mat magnitudeImage = planes[0];//幅度谱 //【6】进行对数尺度(logarithmic scale)缩放 magnitudeImage += Scalar::all(1); log(magnitudeImage, magnitudeImage);//求自然对数 normalize(magnitudeImage, magnitudeImage, 0, 1, NORM_MINMAX); //为了进行灰度级显示,做类型转换 //magnitudeImage.convertTo(magnitudeImage, CV_8UC1, 255, 0); //找到傅里叶谱的最大值的坐标 cv::Point maxLoc;//傅里叶谱的最大值的坐标 minMaxLoc(magnitudeImage, NULL, NULL, NULL, &maxLoc); cv::Mat lpFilter = createLPFilter(magnitudeImage.size(), maxLoc, radius, type, 2); cv::Mat F_lpFilter; F_lpFilter.create(complexI.size(), complexI.type()); for (int r = 0; r < F_lpFilter.rows; r++) { for (int c = 0; c < F_lpFilter.cols; c++) { //分别取出当前位置的快速傅里叶变换和理想低通滤波器的值 Vec2f F_rc = complexI.at<Vec2f>(r, c); float lpFilter_rc = lpFilter.at<float>(r, c); //低通滤波器和图像的快速傅里叶变换对应位置相乘 F_lpFilter.at<Vec2f>(r, c) = F_rc*lpFilter_rc; } } cv::dft(F_lpFilter, dstImage, DFT_SCALE + DFT_INVERSE + DFT_REAL_OUTPUT); /* -- 第九步:同乘以(-1)^(x+y) -- */ for (int r = 0; r < dstImage.rows; r++) { for (int c = 0; c < dstImage.cols; c++) { if ((r + c) % 2) dstImage.at<float>(r, c) *= -1; } } //注意将结果转换 CV_8U 类型 normalize(dstImage, dstImage, 0,255, NORM_MINMAX); dstImage.convertTo(dstImage, CV_8UC1); dstImage = dstImage(Rect(0, 0, srcImage.cols, srcImage.rows)).clone(); }