中值滤波
在使用邻域平均法去噪的同时也使得边界变得模糊。而中值滤波是非线性的图像处理方法,在去噪的同时可以兼顾到边界信息的保留。
中值滤波一般采用一个含有奇数个点的滑动窗口,将窗口中各点灰度值的中值来替代指定点(一般是窗口的中心点)的灰度值。对于奇数个元素,中值是指按大小排序后,排序在中间的数值;对于偶数个元素,中值是指排序后中间两个元素灰度值的平均值。
g(m,n)=Median{f(m-k,n-l),(k,l) on W}
例如选择滤波的窗口是一个一维的窗口,则待处理像素的灰度取这个模板中灰度的中值。常用的窗口还有方形、十字形、圆形和环型。不同形状的窗口产生不同的滤波效果,方形和圆形窗口适合外轮廓线较长的物体图像,而实际形窗口对有尖顶角状的图像效果好。
中值滤波对于消除孤立点和线段的干扰十分有用,尤其是对于二进噪声,但对消除高斯噪声的影响效果不佳。对于一些细节较多的复杂图像,可以多次使用不同的中值滤波。
中值滤波不仅可以去除孤点噪声,而且可以保持图像的边缘特性,不会产生显著的模糊;它的方法是把局部区域的像素按灰度等级进行排序,再取该邻域中灰度的中值作为当前像素的灰度值。步骤如下:
1.将滤波模板(含若干点的滑动窗口)在图像中移动,并将模板中心与图像中的某个像素位置重合;
2.读取模板中各对应像素的灰度值;
3.将这些灰度值从小到大排序;
4.取这一列数据的中间数据,将其赋值给对应模板中心位置的像素。
采用3*3的像素模板,取矩阵中间位置像素替代原像素。代码如下:
//中值滤波
void MedianFilter(BYTE *SrcImage, BYTE *DstImage, int nWidth, int nHeight)
{
int HWS=3;//维数是3维
int H[9]={0,0,0,0,0,0,0,0,0};
int X,Y;//一维坐标转换为二维坐标
int TR1,TG1,TB1;//记录红绿蓝坐标位置
//图像增强:平滑 要获取源图像周围9个点的矩阵乘以模板9个点的矩阵,故一维图像转二维
for (int i=0; i<nWidth*nHeight;i=i+3)
{
//原图:一维矩阵转化为二维矩阵
X=(i/3)%nWidth;//图像在x列
Y=(i/3)/nHeight;//图像在y行
//第一行 第一列 最后一行 最后一列 直接复制
if (X==0 || Y==0 || X==nWidth*3 || Y==nHeight)
{
if (i+2>nWidth*nHeight)
{
break;
}
DstImage[i] = SrcImage[i];
DstImage[i+1] = SrcImage[i+1];
DstImage[i+2] = SrcImage[i+2];
continue;
}
//对图像进行像素求和并取平均值HWS维数
int num=0;
for (int j=Y-HWS/2;j<Y+HWS/2+1;j++)//第j行
{
for (int k=X-HWS/2;k<X+HWS/2+1;k++)//第k列
{
if (j>=0 && k>=0 && k<nWidth && k<nHeight) //防止越界
{
//获取当前位置Red像素k一次增加RGB三个像素 R=G=B
TR1 = j*nWidth*3+k*3;
H[num] = SrcImage[TR1];
//TG1=j*nWidth*3+k*3+1;
//H[num] = SrcImage[TG1];
//TB1=j*nWidth*3+k*3+2;
//H[num]=SrcImage[TB1];
num++;
}
}
}
//排序获取中间值
int temp=0;
for ( int x=0;x<9;x++)
{
for (int y=x;y<9;y++)
{
if (H[x]>H[y])
{
temp=H[x];
H[x]=H[y];
H[y]=temp;
}
}
}
DstImage[i] = H[4];
DstImage[i+1]=H[4];
DstImage[i+2]=H[4];
}
}