均值濾波器
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;
}