均值滤波原理和底层实现(C++实现)

                                                       均值滤波器


1、图像的空间滤波分类

      图像的空间滤波分为线性滤波非线性滤波。

(1)线性滤波

  •  定义:对邻域中的像素的计算为线性运算时,如利用窗口函数进行平滑加权求和的运算,或者某种卷积运算,都可以称为线性滤波。
  •  常见的线性滤波:均值滤波、高斯滤波、盒子滤波、拉普拉斯滤波等等,通常线性滤波器之间只是模版系数不同。

(2)非线性滤波

  •  定义:非线性滤波利用原始图像跟模版之间的一种逻辑关系得到结果。
  • 常见的线型滤波:如最值滤波器,中值滤波器。比较常用的有中值滤波器和双边滤波器。

2、均值滤波应用的场景

     均值模糊可以模糊图像以便得到感兴趣物体的粗略描述,也就是说,去除图像中的不相关细节,其中“不相关”是指与滤波器模板尺寸相比较小的像素区域,从而对图像有一个整体的认知。即为了对感兴趣的物体得到一个大致的整体的描述而模糊一幅图像,忽略细小的细节。


3、均值滤波的缺陷

     均值滤波本身存在着固有的缺陷,即它不能很好地保护图像细节,在图像去噪的同时也破坏了图像的细节部分,从而使图像变得模糊,不能很好地去除噪声点。特别是椒盐噪声


4、均值滤波器的原理

   均值滤波的原理很简单,一般是用下面的系数模版与图像做卷积运算,公式表示为:

                                                                   

 即以当前像素点为中心,求窗口内所有灰度值的和,以其平均值作为中心像素新的灰度值。

下面是一个3*3的均值滤波器模板,均值滤波器的模板有     标准像素平均     和      加权平均        之分。

      左边是标准像素平均的均值滤波器模板,                                       右边是加权平均的均值滤波器模板。

     

 


5、均值滤波实现部分代码

写法1:

for (int i = 0;i < dst->height; i++){
     for (int j = 0; j < dst->width; j++){
         CvScalar s =cvGet2D(dst, i, j);
         double sum =0;//存放窗口中所有像素点灰度值的和
         int num =0;//记录窗口中像素的个数,因为边界上可能不是9个像素
         //求3x3的和
         for (int k = -1; k <= 1; k++)
              for (int m = -1; m <= 1; m++)
                   if (i + k>= 0 && i + k <= 255 && j + m >= 0 && j + m<= 255){
                       CvScalar temp =cvGet2D(dst, i+k, j+m);
                       sum += temp.val[0];
                       num++;
                   }
         s.val[0] = sum/num;
         cvSet2D(dst_sp, i, j, s);
     }
}

写法2:详细写法 

// Mean filter: 均值滤波器
Mat filterMean(cv::Mat img, const int slab)
{
	cvtColor(img, img, CV_BGR2GRAY);  //彩色图像转灰度图像
	Mat retMat = Mat::zeros(img.rows, img.cols, CV_8UC1); //定义一个和图像一样大小的黑色单通道图
	for (int i = 0; i<img.rows; i++)   //行(高)
		for (int j = 0; j<img.cols; j++)   //列(宽)
			retMat.at<uchar>(i, j) = img.at<uchar>(i, j); //at:获得当前位置的像素值

	int* xLocation = new int[slab];
	int* yLocation = new int[slab];
	float sum;
	int index;

	for (int i = slab / 2; i<img.rows - slab / 2; i++)
	{
		xLocation[slab / 2] = i;
		for (int delta = 0; delta <= slab / 2; delta++)
		{
			xLocation[slab / 2 - delta] = i - delta;
			xLocation[slab / 2 + delta] = i + delta;
		}

		for (int j = slab / 2; j<img.cols - slab / 2; j++)
		{
			yLocation[slab / 2] = j;
			for (int delta = 0; delta <= slab / 2; delta++)
			{
				yLocation[slab / 2 - delta] = j - delta;
				yLocation[slab / 2 + delta] = j + delta;
			}

			sum = 0;
			for (int fi = 0; fi < slab; fi++)
			{
				for (int fj = 0; fj < slab; fj++)
				{
					index = fi*slab + fj;
					sum += img.at<uchar>(xLocation[fi], yLocation[fj]);
				}
			}
			retMat.at<uchar>(i, j) = sum / (slab * slab);  //slab*slab为模板面积
		}
	}

	return retMat;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章