2018-11-01 20:52:00 weixin_43418716 阅读数 10753

平滑滤波——matlab图像处理

平滑滤波的目的是消除或尽量减少噪声,改善图像的质量。假设加性噪声是随机独立分布,这样利用图像像素领域的平均或加权平均即可有效地抑制噪声干扰。从信号分析的观点来看,图像平滑本质上是低能滤波,信号的低频部分可通过,高频的噪声信号被阻截。但由于图像边缘也处于高频部分,这样往往带来另一个问题:在对图像进行平滑处理时,往往对图像的细化造成一定程度的损坏。
领域运算可用领域与模版的卷积得到,这极大地方便了计算。
MATLAB中提供的imfliter函数用于实现图像的平滑处理,其调用格式如下。
B=imfliter(A,H):使用多维滤波器H对图像A进行滤波(平滑)。参数A可以是任意维的二值或非奇异数值型矩阵。参数H为矩阵,表示滤波器。H常由函数fspecial输出得到。返回值B与A的维数相同。
B=imfliter(A,H,optional1,optional2,…)

参数类型 说明
X 输入图像的外边界通过X来扩展,X默认值为0
symmetric 输入图像的外部边界通过镜像反射其内部边界来扩展
circular 输入图像的别界通过假设输入图像为周期函数来扩展
relicate 输入图像的外部别界通过复制内部别界的值来扩展
same 输入和输出图像大小相等,默认操作
full 输出图像比输入图像大
corr 使用相关进行滤波(平滑)
conv 使用卷积进行滤波(平滑)

matlab中提供的fspecial函数用于创建二维滤波器:
h=fspecial(type):
type可以是:average,disk,gaussian,laplacian,log,motion,prewitt,sobel,unsharp。

h=fspecial(type,parameters):创建指定类型和指定参数的二维滤波器h。参数parameters为与滤波器有关的参数。
parameters可以是:n,radius,(hsize,sigma),alpha,(n,sigma),(len,theta)。

clear all;
I = imread('cameraman.tif');
subplot(2,2,1);imshow(I);
xlabel('(a)原始图像');
H = fspecial('motion',20,45);
MotionBlur = imfilter(I,H,'replicate');
subplot(2,2,2);imshow(MotionBlur);
xlabel('(b)运动模糊图像');
H=fspecial('disk',10);
blurred = imfilter(I,H,'replicate');
subplot(2,2,3);imshow(blurred);
xlabel('(c)模糊图像');
H=fspecial('unsharp');
sharpened = imfilter(I,H,'replicate');
subplot(2,2,4);imshow(sharpened);
xlabel('(d)锐化图像');

图像的卷积运算

对含有高斯噪声的图像进行平滑处理。

clear all;
I = imread('coins.png');
Inoised = imnoise(I,'gaussian',0.1,0.005);%对图像进行高斯噪声加噪
%制定卷积核
h=ones(3,3)/5;
h(1,1) = 0;
h(1,3) = 0;
h(3,1) = 0;
h(1,3) = 0;
%平滑运算
I2=imfilter(Inoised,h);
subplot(1,3,1);imshow(I);
xlabel('(a)原始图像');
subplot(1,3,2);imshow(Inoised);
xlabel('(b)带噪声图像');
subplot(1,3,3);imshow(I2);
xlabel('(c)平滑后图像');

图像的平滑处理

有问题还请多多指教。刚刚入门。谢谢各位大牛。

2013-04-10 14:51:37 mlkiller 阅读数 4225

本章主要讲图像处理中的模糊处理部分

英文叫做blur, 也叫做smootiing,  中文中叫做模糊或者平滑。

用过photoshop的人都应该知道,滤镜里面就有模糊这个选项,我们现在看看它是怎么实现的。

一含义

   模糊(平滑)是一种常用的图片处理方式,它的作用可以用来降低噪声,还有其他用途

   看一下opencv 里面的公式

               g(i,j) = \sum_{k,l} f(i+k, j+l) h(k,l)

     g(i,j)是目标坐标的像素值, f(i+k,j+l)是k,l这些地方的像素值, h(k,l)是 kernel,  我不知道怎么去准确翻译它的意义,它是过滤器的系数。 

    简单的按照我的思路去理解,就是一个权值,模糊的含义是将所有的像素按照一定的权值进行运算,得到一个比较均衡的结果。

二 类型

类型有很多种:
均值模糊(box blur) 高斯模糊(gaussian blur)  中值模糊(media blur) 二值模糊(bilateral blur)
本文只讲均值模糊和高斯模糊

三 算法

1 均值模糊
   均值模糊很简单就是周边所有的影响都是1,求平均值即可
K = \dfrac{1}{K_{width} \cdot K_{height}} \begin{bmatrix}    1 & 1 & 1 & ... & 1 \\    1 & 1 & 1 & ... & 1 \\    . & . & . & ... & 1 \\    . & . & . & ... & 1 \\    1 & 1 & 1 & ... & 1   \end{bmatrix}
2 高斯模糊
关于高斯模糊的算法,推荐这个文章
根据这个公式计算出系数即可。
上篇文章写得很详细,我就不班门弄斧了。

四均值模糊的代码和效果

     先放上均值模糊的代码
void boxblur(Mat input ,Mat &out, int x, int y)
{
	// accept only char type matrices
	CV_Assert(input.depth() != sizeof(uchar));

	out.create(input.size(),input.type());

	int nChannels = input.channels();
	int nRows = input.rows;
	int nCols = input.cols;

	int size = x * y;
	float kernel = 1.0/size;

	int i,j;
	uchar* p;
	uchar* q;
	uchar R,G,B;

	for( i = x; i < nRows - x; ++i)
	{
		q = out.ptr<uchar>(i);
		for ( j = y; j < nCols - y; ++j)
		{
			float sumR = 0;
			float sumG = 0;
			float sumB = 0;
			for (int k =0; k<x;k++)
			{
				p = input.ptr<uchar>(i-x+k);
				for(int l = 0; l < y;l++)
				{
					sumB += input.at<uchar>(i - x + k,(j + l - y)*nChannels) * kernel;//p[(l + j -y)*nChannels ] * kernel;
					sumG += input.at<uchar>(i - x + k,(j + l - y)*nChannels + 1) * kernel;//p[(l + j -y)*nChannels + 1] * kernel;
					sumR += input.at<uchar>(i - x + k,(j + l - y)*nChannels + 2) * kernel;//p[(l + j -y)*nChannels + 2] * kernel;
				}
			}
			q[j*nChannels] = sumB;
			q[j*nChannels+1] = sumG;
			q[j*nChannels+2] = sumR;
		}
	}


}

红色部分是我想直接用at,而不用指针,但是效率低的厉害。


下图是用指针的相差了20倍。。。可见指针虽然万恶,但是确实是个好东西。



由于size(4,4)图太小看不清, 实际用的是8
原始 opencv 本文


五高斯模糊的代码和效果

代码如下:

void gaussblur(Mat input ,Mat &out, int x, int y)
{
	float sigma = 1.5;
	Mat kernel;
	float pi = 3.1415926;

	kernel.create(x ,y ,CV_32F);

	float mx = x/2.0;
	float my = y/2.0;

       //这里有问题,后面做修正。
	for (int i =0; i< x;i++)
	{
		for (int j =0; j<y;j++)
		{
			kernel.at<float>(i,j) = exp(-1 * ((i - mx) * (i - mx) +(j - my) * (j-my) )/( 2 * sigma * sigma))/(2 * pi * sigma *sigma) ;
		}
	}


    int nChannels = input.channels();
	int nRows = input.rows;
	int nCols = input.cols;

	out.create(input.size(),input.type());
    uchar* p;
	uchar* q;
	float* s;

	for(int  i = x; i < nRows - x; ++i)
	{
		q = out.ptr<uchar>(i);
		for (int j = y; j < nCols - y; ++j)
		{
			float sumR = 0;
			float sumG = 0;
			float sumB = 0;
			for (int k =0; k<x;k++)
			{
				p = input.ptr<uchar>(i-x+k);
				s = kernel.ptr<float>(k); 
				for(int l = 0; l < y;l++)
				{
					sumB += p[(l + j -y)*nChannels ] * s[l];//input.at<uchar>(i - x + k,(j + l - y)*nChannels) * kernel;//
					sumG += p[(l + j -y)*nChannels + 1] *s[l];//input.at<uchar>(i - x + k,(j + l - y)*nChannels + 1) * kernel;//
					sumR += p[(l + j -y)*nChannels + 2] * s[l];//input.at<uchar>(i - x + k,(j + l - y)*nChannels + 2) * kernel;
				}
			}
			q[j*nChannels] = sumB;
			q[j*nChannels+1] = sumG;
			q[j*nChannels+2] = sumR;
		}
	}

	
}

效率如下:

效果图如下:
本文没有考虑边界的情况,所以都是灰色的,可以考虑一下如何处理边界。
原始 opencv 本文

上面代码有两处问题:
第一是在size比较小的时候,这些点的概率之和不等于1,会导致图片出问题。修正如下:

	float sum = 0;
	for (int i =0; i< x;i++)
	{
		for (int j =0; j<y;j++)
		{
			sum+= kernel.at<float>(i,j) = exp(-1 * ((i - mx) * (i - mx) +(j - my) * (j-my) )/( 2 * sigma * sigma))/(2 * pi * sigma *sigma) ;
		}
	}
	for (int i =0; i< x;i++)
	{
		for (int j =0; j<y;j++)
		{
			kernel.at<float>(i,j) = kernel.at<float>(i,j)/ sum ;
		}
	}


第二个问题是本文中sigma 是个固定值,实际上它是个可变值,具体怎么计算,我没有搞清楚,可以查看opencv的源代码,下面文章有参考价值

更新一下参考opencv里面的可以这样计算
sigma = 0.3*((ksize-1)*0.5 - 1) + 0.8 .
修改程序之后发现和原始的高斯函数基本一致,希望广大朋友们多多评论,本人水平有限,很多地方有纰漏,希望能够共同提高。
2018-05-15 14:09:16 Blaze_bxh 阅读数 1802

参考链接:https://docs.opencv.org/3.2.0/d4/d13/tutorial_py_filtering.html

学习目标:

1. 使用不同的低通滤波器模糊图像;

2. 对图像使用定制化滤波器; 

 

2D卷积

低通滤波器用于去除噪音信息,模糊图像,高通滤波器用于寻找图像中的边缘信息。 

Opencv提供的接口函数cv2.filter2D()来对图像做卷积。我们定义一个5x5的均值滤波器核,如下:

 

操作方法:将该滤波器置于一个像素之上,在该滤波器的范围内,所有像素相加,得到均值,用均值替换中间的像素值。该操作作用于图像中的所有像素后,即完成均值滤波。

 

图像模糊(图像平滑)

通过对图像做低通滤波器的卷积操作,实现图像模糊,从而去除噪声信息。实际上,就是从图像中去除了高频信息(如噪点,边缘)。

Opencv提供了四种图像模糊的技术。

1. Averaging

使用标准化的滤波器对图像做卷积,简单地将卷积核区域内的所有像素取均值,并且用均值替换卷积核中心位置对应的像素值。

Opencv 接口:cv2.blur(), cv2.boxFilter(),只需要指定卷积核的宽高即可。

 

2. Gaussian blurring

与上节不同,此处使用高斯核。需要指定核的宽高(正数,奇数),指定xy方向上的偏差,sigmaXsigmaY

高斯模糊可以高效去除图像中的高斯噪音,降低细节层次。

(延伸阅读——高斯噪声 https://blog.csdn.net/sunmc1204953974/article/details/50623071) 

高斯滤波其实就是用高斯分布的方式,生成滤波器中各个位置的权重,再用该滤波器对图像进行卷积操作。

3. Median Blurring

取核区域内的所有像素的中间值,用该值替换核中心的像素值。这种滤波方式,可以高效处理椒盐噪声。在前面介绍的滤波方式中,中间像素的替换值可能是新产生的,而中值滤波,中间值只是被图像中的某个像素值替换。这种方式可以有效减少噪声。

 

4. Bilateral Filtering

双边滤波可以在保留边缘信息的同时,高效去除噪声。但是该操作相比其他滤波器,速度更慢。

高斯滤波器基于位置对各像素进行高斯分布的加权处理,但是他没有考虑到像素之间是否有相同的强度,没有考虑像素是否是边缘像素,所以高斯模糊会将边缘一起模糊掉。

双边滤波器在空间上也使用了高斯滤波器,同时又加了一个高斯滤波器是像素差分函数。空间的高斯函数确保临近像素间的模糊处理,同时,强度差分的高斯函数确保只有和中心像素的强度类似的像素才可以被模糊,因此可以保留边缘信息。


2013-06-28 10:58:42 diarymaggie 阅读数 208

中值滤波容易去除孤立点,线的噪声同时保持图象的边缘;它能很好的去除二值噪声,但对高斯噪声无能为力

#include "cv.h"
#include "highgui.h"

using namespace cv;

#define PI 3.1415926
#define RADIAN(angle) ((angle)*PI/180.0)

int smooth_box[9]={1,1,1,1,1,1,1,1,1};
int smooth_gauss[9]={1,2,1,2,4,2,1,2,1};
int sharpen_laplacian[9]={-1,-1,-1,-1,9,-1,-1,-1,-1};

//平滑和锐化
Mat TemplateOP(Mat& mat)
{
	int M=mat.rows;
	int N=mat.cols;

	float coef;
	int coefArray[9];

#if 0
	coef=(float)(1.0/9.0);
	memcpy(coefArray,smooth_box,sizeof(smooth_box));
#elif 0
	coef=(float)(1.0/16.0);
	memcpy(coefArray,smooth_gauss ,sizeof(smooth_gauss));
#else
	coef=(float)1.0;
	memcpy(coefArray,sharpen_laplacian,sizeof(sharpen_laplacian));
#endif

	Mat ret(M,N,CV_8U);
	for(int i=1;i<M-1;i++)
	{
		for(int j=1;j<N-1;j++)
		{
			float tempNum=0.0;
			int k=0;
			for(int i1=-1;i1<=1;i1++)
				for(int j1=-1;j1<=1;j1++)
					tempNum+=mat.ptr<uchar>(i+i1)[j+j1]*coefArray[k++];
			tempNum*=coef;
			uchar temp;
			if(tempNum>255.0) temp=255;
			else if(tempNum<0.0) temp=0;
			else temp=(uchar)tempNum;

			ret.ptr<uchar>(i)[j]=temp;
		}
	}

	return ret;
}

//中值滤波
Mat MedianFilter(Mat& mat)
{
	int M=mat.rows;
	int N=mat.cols;

	vector<int> nums(9,0);
	Mat ret(M,N,CV_8U);
	for(int i=1;i<M-1;i++)
	{
		for(int j=1;j<N-1;j++)
		{
			int k=0;
			for(int i1=-1;i1<=1;i1++)
				for(int j1=-1;j1<=1;j1++)
					nums[k++]=mat.ptr<uchar>(i+i1)[j+j1];
			sort(nums.begin(),nums.end());
			ret.ptr<uchar>(i)[i]=nums[4];
		}
	}

	return ret;
}

int main()
{
	//读取图像
	Mat image;
	image=imread("circle.jpg",CV_LOAD_IMAGE_GRAYSCALE);

	int M=image.rows;
	int N=image.cols;

	//几何变换

	Mat newImage=TemplateOP(image);
	
	cvNamedWindow("test",CV_WINDOW_AUTOSIZE);
	imshow("test",newImage);

	waitKey(0);
	return 0;
}


2018-03-18 14:51:58 qq_27591163 阅读数 2063

空间滤波:某些邻域处理工作是操作邻域的图像像素值以及相应的雨邻域有相同维数的子图像的值,这些子图像可以被称为滤波器、掩摸、核。在滤波器子图像中的值使系数值,而不是像素值。

线性平滑:对于每一个像素点的灰度值用它的邻域值来代替,其邻域的大小为:N*N,N一般取奇数。线性平滑虽然降低了噪声,但同时也模糊了图像的边缘和细节,这是这一类滤波器的通病。

非线性平滑:不对所有像素都用他的邻域平均值来代替,而是取一个阈值,当像素灰度值与其邻域平均值之差大于已知的阈值时,才用均值来代替。

邻域平均法的3x3模板:

           1 1 1                    1   2   1

1/8  ( 1 1 1)     1/16 (2  4   2)   

            1 1 1                   1    2   1

其中第二种模板的权重不相同,其目的就是为了突出中心点的重要性,所以其权值比较大。

模板选择的越大,则噪声减小的就越明显。

{
	int avg = 0;
	BYTE * m_pdata;
	int width, height;
	m_pdata = getData();
	width = getWidth();
	height = getHeight();
	BYTE* temp = new BYTE[width *height];
	memset(temp, 255, width*height);
	for (int j = 1; j<height - 1; j++)
		for (int i = 1; i < width - 1; i++)
		{
			avg = (int)((m_pdata[(j - 1)*width + (i - 1)] + m_pdata[(j - 1)*width + i] + m_pdata[(j - 1)*width + (i + 1)]
				+ m_pdata[j*width + (i - 1)] + m_pdata[j*width + (i + 1)] + m_pdata[(j + 1)*width + (i - 1)] + m_pdata[(j + 1)*width + i]
				+ m_pdata[(j + 1)*width + (i + 1)]) / 8);
			temp[width*j + i] = avg;
			
		}
	memcpy(m_pdata, temp, width*height);
	delete temp;
} 

中值滤波:

中值滤波是一种非线性滤波,与其对应的中值滤波器也是一种非线性滤波器,中值滤波一般采用一个含有奇数个点的滑动窗口,将窗口中各点的灰度值的种植来替代指定点的灰度值。

二维中值滤波的窗口形状和尺寸设计对于滤波的影响较大。

	if (n >= 3 && n % 2 == 1)
	{
		BYTE * temp = new BYTE[width*height];
		memset(temp, 255, width*height);
		n2 = (n - 1) / 2;
		int chou = (n+n-1) / 2;
		for(int j=n2;j<=height-n2;j++)
			for (int i = n2; i < width - n2; i++)
			{
				int m = 0;
				for (int yy = j - n2; yy <= j + n2; yy++)
				{
					modo[m++] = p_data[yy*width + i];
				}
				for (int xx = i - n2; xx <= i + n2; xx++)
				{
					modo[m++] = p_data[j*width + xx];
				}
				std::sort(modo, modo + m);
				medi = modo[chou];
				temp[j*width + i] = medi;
			}
		memcpy(p_data, temp, width*height);
		delete temp;
	}


没有更多推荐了,返回首页