均值濾波原理和底層實現(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;
}

 

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