opencv实现频域平滑图像

本文是参考opencv低通滤波器这篇文章改进得到的,地址:http://blog.csdn.net/huangli19870217/article/details/1285661。

关于高通滤波,其实只要在createfilter()函数的基础上改写滤波器的函数表示就行,这样就可以实现了,有兴趣的可以自己试试。

#include<opencv2\core\core.hpp>
#include <opencv2\opencv.hpp>
#include <opencv2\highgui\highgui.hpp>
using namespace cv;
using namespace std;
//创建低通滤波器
void createfilter(Mat& lowTemp,float fc)
{
	//参数准备
	int i, j;
	int state = -1;
	double tempD;
	float width, height;
	width = lowTemp.cols;
	height =lowTemp.rows;
	float x, y;
	x = width / 2;
	y = height / 2;

	//D0截止频率
	double D0 = fc * min(lowTemp.rows, lowTemp.cols) / 2.0;

	for (i = 0; i < height; i++)
	{
		float* ptr = lowTemp.ptr<float>(i);
		for (j = 0; j < width; j++)
		{
			if (i > y && j > x)
			{
				state = 3;
			}
			else if (i > y)
			{
				state = 1;
			}
			else if (j > x)
			{
				state = 2;
			}
			else
			{
				state = 0;
			}

			switch (state)
			{
			case 0:
				tempD = (double)(i * i + j * j); tempD = sqrt(tempD); break;
			case 1:
				tempD = (double)((height - i) * (height - i) + j * j); tempD = sqrt(tempD); break;
			case 2:
				tempD = (double)(i * i + (width - j) * (width - j)); tempD = sqrt(tempD); break;
			case 3:
				tempD = (double)((height - i) * (height - i) + (width - j) * (width - j)); tempD = sqrt(tempD); break;
			default:
				break;
			}

			//二维高斯低通滤波器传递函数
			//tempD = exp(-0.5 * pow(tempD / D0, 2));
			//ptr[j*2]= tempD;
			//ptr[2*j+1]= tempD;



			//衰减系数为2的二维指数低通滤波器传递函数
			//tempD = exp(-pow(tempD / D0, 2));
			//ptr[j*2]= tempD;
			//ptr[2*j+1]= tempD;

			//2阶巴特沃思低通滤波器传递函数
			//tempD = 1 / (1 + pow(tempD / D0, 2 * 2));
			//ptr[j*2]= tempD;
			//ptr[2*j+1]= tempD;


			//二维理想低通滤波器传递函数
				if(tempD <= D0)
				{
					ptr[j*2] = 1.0;
			    	ptr[j*2+1] = 1.0;
				}
				else
				{
					ptr[j*2] = 0.0;
			    	ptr[j*2+1] = 0.0;
				}
		}
	}
}

int main(int argc, char ** argv)
{
	//【1】以灰度模式读取原始图像并显示
	Mat srcImg = imread("test1.jpg", 0);
	imshow("原始图像",srcImg);
	//【2】将输入图像延扩到最佳的尺寸,边界用0补充
	int m = getOptimalDFTSize(srcImg.rows);
	int n = getOptimalDFTSize(srcImg.cols);
	//将添加的像素初始化为0.
	Mat padded;
	copyMakeBorder(srcImg, padded, 0, m - srcImg.rows, 0, n - srcImg.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分离成几个单通道数组
	magnitude(planes[0], planes[1], planes[0]);// planes[0] = magnitude  
	Mat magnitudeImage = planes[0];
	//【6】进行对数尺度(logarithmic scale)缩放
	magnitudeImage += Scalar::all(1);
	log(magnitudeImage, magnitudeImage);//求自然对数
	//【7】剪切和重分布幅度图象限
	//若有奇数行或奇数列,进行频谱裁剪      
	magnitudeImage = magnitudeImage(Rect(0, 0, magnitudeImage.cols & -2, magnitudeImage.rows & -2));
	//重新排列傅立叶图像中的象限,使得原点位于图像中心  
	int cx = magnitudeImage.cols / 2;
	int cy = magnitudeImage.rows / 2;
	Mat q0(magnitudeImage, Rect(0, 0, cx, cy));   // ROI区域的左上
	Mat q1(magnitudeImage, Rect(cx, 0, cx, cy));  // ROI区域的右上
	Mat q2(magnitudeImage, Rect(0, cy, cx, cy));  // ROI区域的左下
	Mat q3(magnitudeImage, Rect(cx, cy, cx, cy)); // ROI区域的右下
	//交换象限(左上与右下进行交换)
	Mat tmp;
	q0.copyTo(tmp);
	q3.copyTo(q0);
	tmp.copyTo(q3);
	//交换象限(右上与左下进行交换)
	q1.copyTo(tmp);
	q2.copyTo(q1);
	tmp.copyTo(q2);
	//【8】归一化,用0到1之间的浮点值将矩阵变换为可视的图像格式
	normalize(magnitudeImage, magnitudeImage, 0, 1, CV_MINMAX);

	//【10】创建低通滤波器
	Mat lowTemp = Mat(complexI.size(),complexI.type());
	createfilter(lowTemp, 0.3);
	//将复数转换为幅值
	split(lowTemp, planes); // 将多通道数组complexI分离成几个单通道数组
	magnitude(planes[0], planes[1], planes[0]);// planes[0] = magnitude  
	Mat magFilter = planes[0];
	//进行对数尺度(logarithmic scale)缩放
	magFilter += Scalar::all(1);
	log(magFilter, magFilter);//求自然对数
	//剪切和重分布幅度图象限
	//若有奇数行或奇数列,进行频谱裁剪      
	magFilter = magFilter(Rect(0, 0, magnitudeImage.cols & -2, magnitudeImage.rows & -2));
	//重新排列傅立叶图像中的象限,使得原点位于图像中心  
	int cx1 = magFilter.cols / 2;
	int cy1 = magFilter.rows / 2;
	Mat q01(magFilter, Rect(0, 0, cx1, cy1));   // ROI区域的左上
	Mat q11(magFilter, Rect(cx, 0, cx1, cy1));  // ROI区域的右上
	Mat q21(magFilter, Rect(0, cy1, cx1, cy1));  // ROI区域的左下
	Mat q31(magFilter, Rect(cx1, cy1, cx1, cy1)); // ROI区域的右下
	//交换象限(左上与右下进行交换)
	Mat tmp1;
	q01.copyTo(tmp1);
	q31.copyTo(q01);
	tmp1.copyTo(q31);
	//交换象限(右上与左下进行交换)
	q11.copyTo(tmp1);
	q21.copyTo(q11);
	tmp1.copyTo(q21);
	//归一化,用0到1之间的浮点值将矩阵变换为可视的图像格式
	normalize(magFilter, magFilter, 0, 1, CV_MINMAX);
	imshow("滤波器频谱图", magFilter);

	//【11】频域滤波
	mulSpectrums(complexI, lowTemp, complexI,0);
	//【12】傅里叶反变换
	idft(complexI, complexI, cv::DFT_SCALE);
	//【13】还原原始图像
	split(complexI, planes);
	Mat dft_filter_img;
	dft_filter_img.create(complexI.size(), CV_8UC1);
	planes[0].convertTo(dft_filter_img, CV_8UC1);
	dft_filter_img = dft_filter_img(cv::Rect(0, 0, srcImg.cols, srcImg.rows));//剪切图像

	imshow("低通滤波结果", dft_filter_img);
	waitKey(0);
	return 0;
}

原始图像:


滤波器频谱图:


滤波结果:


  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
opencv中的频域滤波使用傅里叶变换(FFT)进行操作。以下是一些常见的频域滤波操作: 1. 频域低通滤波:通过去除高频部分来平滑图像,常用的方法有理想低通滤波、巴特沃斯低通滤波和高斯低通滤波。 2. 频域高通滤波:通过去除低频部分来增强图像的边缘和细节,常用的方法有理想高通滤波、巴特沃斯高通滤波和高斯高通滤波。 3. 频域带通滤波:通过保留一定频率范围内的信息来增强图像的某些频率成分。 在OpenCV中,可以使用dft函数进行傅里叶变换,使用idft函数进行逆变换。可以使用getOptimalDFTSize函数来获取最佳尺寸。下面是一个示例代码,演示如何进行频域滤波: ```python import cv2 import numpy as np # 读取图像 image = cv2.imread('image.jpg', 0) # 将图像转换为频域 dft = cv2.dft(np.float32(image), flags=cv2.DFT_COMPLEX_OUTPUT) dft_shift = np.fft.fftshift(dft) # 创建一个掩模,中心为1,其余为0 rows, cols = image.shape mask = np.zeros((rows, cols, 2), np.uint8) mask[int(rows/2)-30:int(rows/2)+30, int(cols/2)-30:int(cols/2)+30] = 1 # 应用滤波器 dft_shift = dft_shift * mask # 将频域图像转换回空域图像 f_ishift = np.fft.ifftshift(dft_shift) image_filtered = cv2.idft(f_ishift) image_filtered = cv2.magnitude(image_filtered[:, :, 0], image_filtered[:, :, 1]) # 显示原始图像和滤波后的图像 cv2.imshow('Original', image) cv2.imshow('Filtered', image_filtered) cv2.waitKey(0) cv2.destroyAllWindows() ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值