均值滤波属于线性滤波方法,中值滤波属于非线性方法。他们都属于空间域内平滑方法。对于给定的图像f(x, y)中的每个像素点(x, y),取其邻域Sxy,设Sxy含有M个像素,取其平均值做为处理后所得图像像素点(x, y)处的灰度值,该方法称为均值滤波,而取其中值做为处理后所得图像像素带点(x, y)处的灰度,称为中值滤波。
均值滤波方法能有效地抑制噪声,但同时也由于平均而引起了模糊现象,模糊程度与邻域半径成正比,中值滤波方法主要功能是让周围像素灰度值差别比较大的像素改为选取与周围的像素值接近的值,从而可以消除孤立的噪声点,所以中值滤波对于滤除图像昂的椒盐噪声非常有效,中值滤波可以做到既去除噪声又能保护图像的边缘,从而获得较满意的复原效果。
下面是算法的具体实现,采用的滤波窗口大小为3*3和5*5(附,获取图像颜色类型方法:灰度、二值、24位彩色)
/// <summary>
/// 图像格式类型
/// </summary>
public enum ImageFormats {
/// <summary>
/// 二值图
/// </summary>
BinaryzationFormat = 1,
/// <summary>
/// 灰度图
/// </summary>
GrayFormat = 2,
/// <summary>
/// 彩色图
/// </summary>
ColorFormat = 3,
/// <summary>
/// 未知
/// </summary>
UnKnown = -1
}
/// <summary>
/// 图像滤波
/// </summary>
/// <param name="srcBmp">原始图像</param>
/// <param name="filteringType">滤波算法类型</param>
/// <param name="imageFormat">图像颜色格式</param>
/// <param name="dstBmp">目标图像</param>
/// <returns>处理成功 true 失败 false</returns>
public static bool Filtering(Bitmap srcBmp, ScanStruction scanStruction, FilteringType filteringType, ImageFormats imageFormat, out Bitmap dstBmp) {
if (srcBmp == null) {
dstBmp = null;
return false;
}
Bitmap grayBmp = null;
dstBmp = new Bitmap(srcBmp);
BitmapData bmpDataGray = null;
if (imageFormat == ImageFormats.ColorFormat) {
ToGray(srcBmp, out grayBmp);
bmpDataGray = grayBmp.LockBits(new Rectangle(0, 0, grayBmp.Width, grayBmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
}
BitmapData bmpDataSrc = srcBmp.LockBits(new Rectangle(0, 0, srcBmp.Width, srcBmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
BitmapData bmpDataDst = dstBmp.LockBits(new Rectangle(0, 0, dstBmp.Width, dstBmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
unsafe {
byte[] grayValueArray = new byte[25];
long[] index = new long[25];
for (int i = 0; i < 25; i++) {
grayValueArray[i] = 255;
}
byte* ptrSrc = (byte*)bmpDataSrc.Scan0;
byte* ptrDst = (byte*)bmpDataDst.Scan0;
byte* ptrGray = null;
if (imageFormat == ImageFormats.ColorFormat) {
ptrGray = (byte*)bmpDataGray.Scan0;
}
switch (filteringType) {
case FilteringType.MedianFiltering://中值滤波
switch (scanStruction) {
case ScanStruction.Horizontal3Bits:
for (int i = 0; i < bmpDataSrc.Height; i++) {
for (int j = 0; j < bmpDataSrc.Width; j++) {
if (imageFormat == ImageFormats.ColorFormat) {
grayValueArray[0] = ptrGray[Math.Abs(i - 1) % bmpDataSrc.Height * bmpDataSrc.Stride + Math.Abs(j - 1) % bmpDataSrc.Width * 3];
grayValueArray[1] = ptrGray[Math.Abs(i - 1) % bmpDataSrc.Height * bmpDataSrc.Stride + j * 3];
grayValueArray[2] = ptrGray[Math.Abs(i - 1) % bmpDataSrc.Height * bmpDataSrc.Stride + (j + 1) % bmpDataSrc.Width * 3];
grayValueArray[3] = ptrGray[i * bmpDataSrc.Stride + Math.Abs(j - 1) % bmpDataSrc.Width * 3];
grayValueArray[4] = ptrGray[i * bmpDataSrc.Stride + j * 3];
grayValueArray[5] = ptrGray[i * bmpDataSrc.Stride + (j + 1) % bmpDataSrc.Width * 3];
grayValueArray[6] = ptrGray[(i + 1) % bmpDataSrc.Height * bmpDataSrc.Stride + Math.Abs(j - 1) % bmpDataSrc.Width * 3];
grayValueArray[7] = ptrGray[(i + 1) % bmpDataSrc.Height * bmpDataSrc.Stride + j * 3];
grayValueArray[8] = ptrGray[(i + 1) % bmpDataSrc.Height * bmpDataSrc.Stride + (j + 1) % bmpDataSrc.Width * 3];
index[0] = Math.Abs(i - 1) % bmpDataSrc.Height * bmpDataSrc.Stride + Math.Abs(j - 1) % bmpDataSrc.Width * 3;
index[1] = Math.Abs(i - 1) % bmpDataSrc.Height * bmpDataSrc.Stride + j * 3;
index[2] = Math.Abs(i - 1) % bmpDataSrc.Height * bmpDataSrc.Stride + (j + 1) % bmpDataSrc.Width * 3;
index[3] = i * bmpDataSrc.Stride + Math.Abs(j - 1) % bmpDataSrc.Width * 3;
index[4] = i * bmpDataSrc.Stride + j * 3;
index[5] = i * bmpDataSrc.Stride + (j + 1) % bmpDataSrc.Width * 3;
index[6] = (i + 1) % bmpDataSrc.Height * bmpDataSrc.Stride + Math.Abs(j - 1) % bmpDataSrc.Width * 3;
index[7] = (i + 1) % bmpDataSrc.Height * bmpDataSrc.Stride + j * 3;
index[8] = (i + 1) % bmpDataSrc.Height * bmpDataSrc.Stride + (j + 1) % bmpDataSrc.Width * 3;
Array.Sort(grayValueArray, index);
ptrDst[i * bmpDataDst.Stride + j * 3] = ptrSrc[index[4]];
ptrDst[i * bmpDataDst.Stride + j * 3 + 1] = ptrSrc[index[4] + 1];
ptrDst[i * bmpDataDst.Stride + j * 3 + 2] = ptrSrc[index[4] + 2];
}
else {
grayValueArray[0] = ptrSrc[Math.Abs(i - 1) % bmpDataSrc.Height * bmpDataSrc.Stride + Math.Abs(j - 1) % bmpDataSrc.Width * 3];
grayValueArray[1] = ptrSrc[Math.Abs(i - 1) % bmpDataSrc.Height * bmpDataSrc.Stride + j * 3];
grayValueArray[2] = ptrSrc[Math.Abs(i - 1) % bmpDataSrc.Height * bmpDataSrc.Stride + (j + 1) % bmpDataSrc.Width * 3];
grayValueArray[3] = ptrSrc[i * bmpDataSrc.Stride + Math.Abs(j - 1) % bmpDataSrc.Width * 3];
grayValueArray[4] = ptrSrc[i * bmpDataSrc.Stride + j * 3];
grayValueArray[5] = ptrSrc[i * bmpDataSrc.Stride + (j + 1) % bmpDataSrc.Width * 3];
grayValueArray[6] = ptrSrc[(i + 1) % bmpDataSrc.Height * bmpDataSrc.Stride + Math.Abs(j - 1) % bmpDataSrc.Width * 3];
grayValueArray[7] = ptrSrc[(i + 1) % bmpDataSrc.Height * bmpDataSrc.Stride + j * 3];
grayValueArray[8] = ptrSrc[(i + 1) % bmpDataSrc.Height * bmpDataSrc.Stride + (j + 1) % bmpDataSrc.Width * 3];
Array.Sort(grayValueArray);
ptrDst[i * bmpDataDst.Stride + j * 3] = (byte)grayValueArray[4];
ptrDst[i * bmpDataDst.Stride + j * 3 + 1] = (byte)grayValueArray[4];
ptrDst[i * bmpDataDst.Stride + j * 3 + 2] = (byte)grayValueArray[4];
}
}
}
break;
case ScanStruction.Square5Bits://5*5
for (int i = 0; i < bmpDataSrc.Height; i++) {
for (int j = 0; j < bmpDataSrc.Width; j++) {
if (imageFormat == ImageFormats.ColorFormat) {
grayValueArray[0] = ptrGray[Math.Abs(i - 2) % bmpDataSrc.Height * bmpDataSrc.Stride + Math.Abs(j - 2) % bmpDataSrc.Width * 3];
grayValueArray[1] = ptrGray[Math.Abs(i - 2) % bmpDataSrc.Height * bmpDataSrc.Stride + Math.Abs(j - 1) % bmpDataSrc.Width * 3];
grayValueArray[2] = ptrGray[Math.Abs(i - 2) % bmpDataSrc.Height * bmpDataSrc.Stride +