1、中值濾波
中值濾波是對一個滑動窗口內的諸像素灰度值排序,用其中值代替窗口中心象素的原來灰度值,它是一種非線性的圖像平滑法,它對脈衝干擾級椒鹽噪聲的抑制效果好,在抑制隨機噪聲的同時能有效保護邊緣少受模糊。
二維中值濾波算法是:對於一幅圖像的象素矩陣,取以目標象素爲中心的一個子矩陣窗口,這個窗口可以是3*3 ,5*5 等根據需要選取,對窗口內的象素灰度排序,取中間一個值作爲目標象素的新灰度值。
步驟:
1:通過從圖像中的某個採樣窗口取出奇數個數據進行排序
在這裏,我們選用的排序方法是冒泡排序
2:用排序後的中值取代要處理的數據即可
一般的,中值濾波對圖像的邊界用0做擴張,所以對邊界可能會出現扭曲。在這裏,我對邊界進行了填充,用裏圈的值來填充外圈的值。若要用0填充外圈,可將imagedatafilter初始化爲0:
memset(imagedatafilter,0,linebyte*bmpHeight);
如果這樣,那填充的那個循環就可以去掉不要了,具體代碼如下:#include <cstring>
#include <windows.h>
#include"readbmp.h"
#include"savebmp.h"
#include<assert.h>
#define iFilterW 3
#define iFilterH 3
unsigned char GetMedianNum(int * bArray, int iFilterLen)
{
int i, j;// 循環變量
unsigned char bTemp;
// 用冒泡法對數組進行排序
for (j = 0; j < iFilterLen - 1; j++)
{
for (i = 0; i < iFilterLen - j - 1; i++)
{
if (bArray[i] > bArray[i + 1])
{
// 互換
bTemp = bArray[i];
bArray[i] = bArray[i + 1];
bArray[i + 1] = bTemp;
}
}
}
// 計算中值
if ((iFilterLen & 1) > 0)
{
// 數組有奇數個元素,返回中間一個元素
bTemp = bArray[(iFilterLen + 1) / 2];
}
else
{
// 數組有偶數個元素,返回中間兩個元素平均值
bTemp = (bArray[iFilterLen / 2] + bArray[iFilterLen / 2 + 1]) / 2;
}
return bTemp;
}
void image_filter_median()
{
char readPath[] = "D:\\C++_file\\image_deal_C++\\IMAGE_JIEQU\\jiaoyan.bmp";
readBmp(readPath);
unsigned char *imagedatafilter;
unsigned char *imagedata;
imagedata = pBmpBuf;
int aValue[iFilterH*iFilterW]; // 指向濾波器數組的指針
int lineByte = (bmpWidth * biBitCount / 8 + 3) / 4 * 4;
imagedatafilter = new unsigned char[lineByte * bmpHeight];
int iFilterHM= (iFilterH - 1)/ 2;
int iFilterWM = (iFilterW - 1) / 2;
for (int i = iFilterHM; i < bmpHeight - iFilterHM; i++)
for (int j = iFilterWM; j < bmpWidth - iFilterWM; j++)
for (int k = 0; k < 3; k++)
{
for (int m = 0; m< iFilterH; m++)
for (int n = 0; n < iFilterW; n++)
{
aValue[m * iFilterW + n] = *(imagedata + lineByte* (i+m-1) + (j + n-1) * 3 + k);
}
*(imagedatafilter + bmpWidth * 3 * i + j * 3 + k) = GetMedianNum(aValue, iFilterH * iFilterW);
}
for (int i = 0; i < bmpHeight; i++)
for (int j = 0; j < bmpWidth; j++)
for (int k = 0; k < 3; k++)
{
if ((i<iFilterHM) && (j<iFilterWM))
*(imagedatafilter + lineByte * i + j * 3 + k) = *(imagedatafilter + lineByte* (i + iFilterHM) + (j + iFilterWM) * 3 + k);
else if ((i<iFilterHM) && (j>=iFilterWM)&&(j<(bmpWidth - iFilterWM)))
*(imagedatafilter + lineByte * i + j * 3 + k) = *(imagedatafilter + lineByte* (i + iFilterHM) + j * 3 + k);
else if ((i<iFilterHM) && ( j >= (bmpWidth - iFilterWM)))
*(imagedatafilter + lineByte * i + j * 3 + k) = *(imagedatafilter + lineByte* (i + iFilterHM) + (j - iFilterWM) * 3 + k);
else if ((i>=iFilterHM) && i <(bmpHeight - iFilterHM) && (j< iFilterWM))
*(imagedatafilter + lineByte * i + j * 3 + k) = *(imagedatafilter + lineByte* i + (j + iFilterWM) * 3 + k);
else if ((i>=iFilterHM) && i < (bmpHeight - iFilterHM) && (j >= (bmpWidth - iFilterWM)))
*(imagedatafilter + lineByte * i + j * 3 + k) = *(imagedatafilter + lineByte* i + (j - iFilterWM) * 3 + k);
else if ((i >= (bmpHeight - iFilterHM)) && (j< iFilterWM))
*(imagedatafilter + lineByte * i + j * 3 + k) = *(imagedatafilter + lineByte* (i - iFilterHM) + (j + iFilterWM) * 3 + k);
else if ((i >= (bmpHeight - iFilterHM)) && (j>= iFilterWM)&&(j<(bmpWidth - iFilterWM)))
*(imagedatafilter + lineByte * i + j * 3 + k) = *(imagedatafilter + lineByte* (i - iFilterHM) + j * 3 + k);
else if ((i >= (bmpHeight - iFilterHM)) && ( j >= (bmpWidth - iFilterWM)))
*(imagedatafilter + lineByte * i + j * 3 + k) = *(imagedatafilter + lineByte* (i - iFilterHM) + (j - iFilterWM) * 3 + k);
}
char writePath[] = "D:\\C++_file\\image_deal_C++\\IMAGE_JIEQU\\mm.bmp";
saveBmp(writePath, imagedatafilter, bmpWidth, bmpHeight, biBitCount, pColorTable);
printf("中值濾波操作完成,請查看bmp文件。\n\n");
}
原圖:
濾波後: