Opencv + FFTW3 图象高斯高低通滤波

1:LPF
公式:out(i,j) = exp(-((i-M/2)^2+(j-N/2)^2)/2/sigma^2);
代码:
        
void LPF_Fliter(vector<double>&data, int cols, int rows, double gamma)
{
	float gamma22 = 2 * gamma*gamma;
	float temp = 0.0;
	int halfRows = cvRound(rows / 2);
	int halfCols = cvRound(cols / 2);
	char debug[12] = { 0 };
	for (int j = 1; j <= rows; j++)
	{
		for (int i = 1; i <= cols; i++)
		{
			temp = (pow(j - halfRows, 2) + pow(i - halfCols, 2));
			data.push_back(exp(-temp / gamma22));
		}
	}
}

2:HPF:


公式:out(i,j) = 1 - exp(-((i-M/2)^2+(j-N/2)^2)/2/sigma^2);
代码:
 
void HPF_Fliter(vector<double>&data, int cols, int rows, double gamma)
{
#if 1
	float gamma22 = 2 * gamma*gamma;
	float temp = 0.0;
	int halfRows = cvRound(rows / 2);
	int halfCols = cvRound(cols / 2);
	char debug[12] = { 0 };
	for (int j = 1; j <= rows; j++)
	{
		for (int i = 1; i <= cols; i++)
		{
			temp = (pow(j - halfRows, 2) + pow(i - halfCols, 2));
			data.push_back(1.0 - exp(-temp / gamma22));
		}
	}
#else
	
	fstream readFile("C:\\Users\\Tony\\Desktop\\debug.txt", ios::in);
	string temp;
	int lineCount = 0;
	while (getline(readFile, temp))
	{
		vector<string>dest;
		split(temp, "\t", dest);
		lineCount++;
		if (dest.size() > 1)
		{
			for (int i = 0; i < dest.size(); i++)
			{
				//printf_s("%s\tn", dest.at(i));
				data.push_back(atof(dest.at(i).c_str()));

			}
		}

		//printf_s("\n");
	}
#endif
}


//生成频谱图:
                   
//生成频谱模板
void test()
{
	int  i;
	fftw_complex*din, *out;
	fftw_plan p,backp;

	Mat image = imread("C:\\Users\\Tony\\Desktop\\Image\\lenaCopy.bmp", CV_LOAD_IMAGE_GRAYSCALE);
	din = (fftw_complex *)fftw_malloc(sizeof(fftw_complex)*image.cols*image.rows);
	out = (fftw_complex *)fftw_malloc(sizeof(fftw_complex)*image.cols*image.rows);


	Mat floatImage(image.size(), CV_32FC1);
	image.convertTo(floatImage, CV_32FC1);
	

	for (size_t j = 0; j < image.rows; j++)
	{
		for (size_t i = 0; i < image.cols; i++)
		{
			din[i + j*image.cols][0] = *floatImage.ptr<float>(j, i);
			din[i + j*image.cols][1] = 0;
		}
	}
	//forward fft
	p = fftw_plan_dft_2d(image.rows, image.cols, din, out, FFTW_FORWARD, FFTW_ESTIMATE);
	fftw_execute(p);

	Mat Resource(image.size(), CV_32FC1);
	Mat Imsource(image.size(), CV_32FC1);
	for (size_t j = 0; j < image.rows; j++)
	{
		for (size_t i = 0; i < image.cols; i++)
		{
			*Resource.ptr<float>(j, i) = out[i + j*image.cols][0];//实部
			*Imsource.ptr<float>(j, i) = out[i + j*image.cols][1];//虚部
		}
	}
	
	Mat Redest(image.size(), CV_32FC1);
	Mat Imdest(image.size(), CV_32FC1);
	fftshift(Resource, Redest);
	fftshift(Imsource, Imdest);
	
	Mat absImage(image.size(), CV_32FC1);
	for (size_t j = 0; j < image.rows; j++)
	{
		for (size_t i = 0; i < image.cols; i++)
		{
			*absImage.ptr<float>(j, i) = sqrt(pow(*Redest.ptr<float>(j, i), 2) + pow(*Imdest.ptr<float>(j, i), 2));
		}
	}
	
	
	absImage += Scalar::all(1);
	Mat logImage(image.size(), CV_32FC1);
	log(absImage, logImage);
	//SaveData(logImage);
	double min = 0.0, max = 0.0;
	minMaxLoc(logImage, &min, &max);
	double scale = 255/(max-min);
	double shift = -min*scale;
	Mat myImage(image.size(), CV_8UC1);
	convertScaleAbs(logImage, myImage, scale, shift);
	imwrite("C:\\Users\\Tony\\Desktop\\lenaCopy.bmp", myImage);
}

高低通滤波:
void testOne()
{
	int  i;
	fftw_complex*din, *out;
	fftw_plan p, backp;

	Mat image = imread("C:\\Users\\Tony\\Desktop\\blur.bmp", CV_LOAD_IMAGE_GRAYSCALE);
	din = (fftw_complex *)fftw_malloc(sizeof(fftw_complex)*image.cols*image.rows);
	out = (fftw_complex *)fftw_malloc(sizeof(fftw_complex)*image.cols*image.rows);


	Mat floatImage(image.size(), CV_32FC1);
	image.convertTo(floatImage, CV_32FC1);
	for (size_t j = 0; j < image.rows; j++)
	{
		for (size_t i = 0; i < image.cols; i++)
		{
			din[i + j*image.cols][0] = *floatImage.ptr<float>(j, i);
			din[i + j*image.cols][1] = 0.0;
		}
	}
	//forward fft
	p = fftw_plan_dft_2d(image.rows, image.cols, din, out, FFTW_FORWARD, FFTW_ESTIMATE);
	fftw_execute(p);

	
	//图像频谱中心化
	Mat Resource(image.size(), CV_32FC1);
	Mat Imsource(image.size(), CV_32FC1);//虚部
	Mat Redest(image.size(), CV_32FC1);
	Mat Imdest(image.size(), CV_32FC1);//虚部
	for (size_t j = 0; j < image.rows; j++)
	{
		for (size_t i = 0; i < image.cols; i++)
		{
			*Resource.ptr<float>(j, i) = out[i + j*image.cols][0];//实部
			*Imsource.ptr<float>(j, i) = out[i + j*image.cols][1];//虚部
		}
	}


	fftshift(Resource, Redest);
	fftshift(Imsource, Imdest);//虚部



	//图像频谱乘以不通的数据,构建滤波
	vector<double>data;
	HPF_Fliter(data, image.cols, image.rows, 10);
	//LPF_Fliter(data, image.cols, image.rows, 100);
	Mat filterRe(image.size(), CV_32FC1);
	Mat filterIm(image.size(), CV_32FC1);//虚部
	for (size_t j = 0; j < image.rows; j++)
	{
		for (size_t i = 0; i < image.cols; i++)
		{
			*filterRe.ptr<float>(j, i) = *Redest.ptr<float>(j, i) * data.at(j*image.cols + i);//实部
			*filterIm.ptr<float>(j, i) = *Imdest.ptr<float>(j, i) * data.at(j*image.cols + i);//虚部
		 }
	}




	//图像频谱逆中心化
	Mat NotCenterRedest(image.size(), CV_32FC1);
	Mat NotCenterImdest(image.size(), CV_32FC1);//虚部
	ifftShift(filterRe, NotCenterRedest);
	ifftShift(filterIm, NotCenterImdest);//虚部


	//重新构造复数,傅里叶反变换
	fftw_complex *spectrum = (fftw_complex *)fftw_malloc(sizeof(fftw_complex)*image.cols*image.rows);
	for (size_t j = 0; j < image.rows; j++)
	{
		for (size_t i = 0; i < image.cols; i++)
		{
			spectrum[j*image.cols + i][0] = *NotCenterRedest.ptr<float>(j, i);//实部
			spectrum[j*image.cols + i][1] = *NotCenterImdest.ptr<float>(j, i);//虚部
		}
	}

	

	//傅里叶反变换
	fftw_complex *result = (fftw_complex *)fftw_malloc(sizeof(fftw_complex)*image.cols*image.rows);
	backp = fftw_plan_dft_2d(image.rows, image.cols, spectrum, result, FFTW_BACKWARD, FFTW_ESTIMATE);
	fftw_execute(backp);
	int size = image.cols*image.rows;

	Mat IvsResource(image.size(), CV_32FC1, Scalar::all(0));
	//Mat IvsImsource(image.size(), CV_32FC1, Scalar::all(0));//虚部
	//Mat ifftImage(image.size(), CV_32FC1, Scalar::all(0));
	Mat myImage(image.size(), CV_8UC1);
	for (size_t j = 0; j < image.rows; j++)
	{
		for (size_t i = 0; i < image.cols; i++)
		{
			*IvsResource.ptr<float>(j, i) = result[i + j*image.cols][0] / size;//实部
			//*IvsImsource.ptr<float>(j, i) = result[i + j*image.cols][1] / size;//虚部
			//*ifftImage.ptr<float>(j, i) = sqrt(pow(result[i + j*image.cols][0], 2) + pow(result[i + j*image.cols][1], 2));
			*myImage.ptr<byte>(j, i) = cvRound(abs(*IvsResource.ptr<float>(j, i)));//实部
		}
	}
	//SaveData(IvsResource);
	imwrite("C:\\Users\\Tony\\Desktop\\Copy.bmp", myImage);

	Mat gammaImage(image.size(), CV_8UC1);
	GammaCorrection(myImage, gammaImage, 0.3);

	//释放资源
	fftw_destroy_plan(p);
	fftw_destroy_plan(backp);
	fftw_free(din);
	fftw_free(out);
	fftw_free(result);
}


#include <fftw3.h> #include <opencv2/opencv.hpp> #include <cmath> // 1. 读取灰度图像 cv::Mat readGrayscale(const char* path) { cv::Mat img = cv::imread(path, cv::IMREAD_GRAYSCALE); if(img.empty()) throw std::runtime_error("Failed to load image"); return img; } // 2. FFT变换 (返回复数矩阵) fftw_complex* imageToFFT(const cv::Mat& img) { int w = img.cols, h = img.rows; // 分配内存 fftw_complex* in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * w * h); fftw_complex* out = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * w * h); // 初始化实数转复数 for(int i=0; i<h; i++) { uchar* p = img.ptr<uchar>(i); for(int j=0; j<w; j++) { in[i*w+j][0] = p[j] / 255.0; // 实部 [0,1] in[i*w+j][1] = 0; // 虚部 } } // 创建FFT计划并执行 fftw_plan plan = fftw_plan_dft_2d(h, w, in, out, FFTW_FORWARD, FFTW_ESTIMATE); fftw_execute(plan); fftw_destroy_plan(plan); fftw_free(in); return out; } // 3. 频域可视化(幅度谱) cv::Mat visualizeSpectrum(fftw_complex* freqData, int w, int h) { cv::Mat mag(h, w, CV_32F); for(int i=0; i<h; i++) { float* p = mag.ptr<float>(i); for(int j=0; j<w; j++) { double re = freqData[i*w+j][0]; double im = freqData[i*w+j][1]; p[j] = log(1 + sqrt(re*re + im*im)); // 对数增强 } } // 归一化并转换类型 cv::normalize(mag, mag, 0, 1, cv::NORM_MINMAX); cv::Mat display; mag.convertTo(display, CV_8U, 255); // 中心化 (FFTShift) int cx = w/2, cy = h/2; cv::Mat q0(display, cv::Rect(0, 0, cx, cy)); // 左上 cv::Mat q1(display, cv::Rect(cx, 0, cx, cy)); // 右上 cv::Mat q2(display, cv::Rect(0, cy, cx, cy)); // 左下 cv::Mat q3(display, cv::Rect(cx, cy, cx, cy)); // 右下 // 交换象限 cv::Mat tmp; q0.copyTo(tmp); q3.copyTo(q0); tmp.copyTo(q3); q1.copyTo(tmp); q2.copyTo(q1); tmp.copyTo(q2); return display; } // 4. 低通滤波高斯滤波器) void gaussianLowPass(fftw_complex* freqData, int w, int h, double cutoff) { int cx = w/2, cy = h/2; for(int y=0; y<h; y++) { for(int x=0; x<w; x++) { // 计算距离中心点距离 double dx = (x - cx) * 1.0 / cx; double dy = (y - cy) * 1.0 / cy; double d = sqrt(dx*dx + dy*dy); // 应用高斯函数 double factor = exp(-d*d / (2*cutoff*cutoff)); freqData[y*w+x][0] *= factor; freqData[y*w+x][1] *= factor; } } } // 5. IFFT逆变换 cv::Mat ifftToImage(fftw_complex* freqData, int w, int h) { fftw_complex* out = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*w*h); fftw_plan plan = fftw_plan_dft_2d(h, w, freqData, out, FFTW_BACKWARD, FFTW_ESTIMATE); fftw_execute(plan); // 转换为灰度图像 cv::Mat result(h, w, CV_8U); for(int i=0; i<h; i++) { uchar* p = result.ptr<uchar>(i); for(int j=0; j<w; j++) { // 取实数部分并缩放到[0,255] double val = out[i*w+j][0]/(w*h); // FFTW未归一化 p[j] = cv::saturate_cast<uchar>(val*255); } } fftw_destroy_plan(plan); fftw_free(out); return result; } // 6. 计算MSE和PSNR void evaluate(const cv::Mat& orig, const cv::Mat& recon, double& mse, double& psnr) { mse = 0; const int N = orig.total(); for(int i=0; i<orig.rows; i++) { const uchar* p1 = orig.ptr<uchar>(i); const uchar* p2 = recon.ptr<uchar>(i); for(int j=0; j<orig.cols; j++) { double diff = p1[j] - p2[j]; mse += diff*diff; } } mse /= N; if(mse < 1e-10) psnr = 100; // 防止除0 else psnr = 10 * log10(255*255 / mse); } int main() { // 1. 读取灰度图像 cv::Mat img = readGrayscale("input.jpg"); // 2. 执行FFT fftw_complex* freq = imageToFFT(img); // 3. 可视化频域 cv::Mat spectrum = visualizeSpectrum(freq, img.cols, img.rows); cv::imwrite("spectrum.jpg", spectrum); // 4. 低通滤波 (0.2为截止频率参数) gaussianLowPass(freq, img.cols, img.rows, 0.2); // 5. 逆变换重建图像 cv::Mat reconstructed = ifftToImage(freq, img.cols, img.rows); cv::imwrite("reconstructed.jpg", reconstructed); // 6. 计算质量指标 double mse, psnr; evaluate(img, reconstructed, mse, psnr); printf("MSE: %.2f\tPSNR: %.2f dB\n", mse, psnr); fftw_free(freq); return 0; }
最新发布
06-05
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值