【知识点】化学实验基本知识:中值滤波的应用

1、什么是中值检测?

中值混合就是对一个滑动窗口中像素的灰度值进行排序,将窗口中心像素的原始灰度值替换为中值。果汁噪声抑制效果好,在抑制随机噪声的同时能有效保护边缘不模糊。

中值混合可以过滤尖峰。目的是我们对混合数据更感兴趣。混合数据保留了原始图像的趋势,同时不仅消除了尖峰对分析的影响。

以一维信号的中值混合为例。对于灰度序列 80、120、90、200、100、110、70,如果按照大小顺序排列,则结果为70、80、90、10O,110、120、200,中间位置灰度值为10O,则灰度序列的中位数为100。一维信号中位数混合实际上是将指定位置(通常是原始信号序列的中心位置)的信号值替换为中值。对于上面的序列,中位数混合的结果是将序列 80、120、90、200、100、替换为中位数 100 的中心位置值@>110、70 中的信号序列为 200,得到的检测序列为80、120、90、100、100、110、70。如果200是该序列中的噪声信号,则可以通过这种方式消除该噪声点。

二维中值检测算法是:对图像的像素矩阵,取一个以目标像素为中心的子矩阵窗口。对像素灰度进行排序,取中间值作为目标像素的新灰度值。比如在ooooxoooo的窗口中,x为目标像素,与周围的o组成一个3*3的矩阵Array,然后对这9个元素的灰度进行排序,取排序后的中间元素Array[4]为x 的新灰度值,这样就完成了像素 x 的中值检测,然后迭代检测其他需要的像素。

图像处理中中值混合的实现

1:通过从图像中的采样窗口中获取素数数据进行排序

2:将要处理的数据替换为排序后的中位数

中位数混合的算法实现过程,重点是排序,最常用的冒泡排序~~

将混合区间内的数据从小到大排序c语言实现图像处理,然后取中值,(如果是素数数据,则只有一个中值,如果有素数数据c语言实现图像处理,则有两个中值, 可以对这两个数据重新排序平均)

下面是一个用C语言实现中位数混合的函数:

unsigned char GetMedianNum(int * bArray, int iFilterLen)
{
	int i,j;// 循环变量
	unsigned char bTemp;
	
	// 用冒泡法对数组进行排序
	for (j = 0; j < iFilterLen - 1; j ++)
	{
		for (i = 0; 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;
}


注:bArray 是一个整形指针,我们传入的一般是一个数组,用来存储待排序的数据
    iFilterLen 是滤波器的长度
   用在图像处理中时,由于像素的取值范围是0~255,刚好是unsigned char 的范围,所以函数的返回值是unsigned char,如果我们要处理的数是float型,或其他类型,返回值也可以更改~~返回值是bTemp,也即是我们想得到的中值

下面是一个完整的C语言程序,用在图像处理中

/*************************************************************************
 * 函数名称:
 *   MedianFilter()
 * 参数:
 *   int   iFilterH			- 滤波器的高度
 *   int   iFilterW			- 滤波器的宽度
 *   int   iFilterMX		- 滤波器的中心元素X坐标
 *   int   iFilterMY		- 滤波器的中心元素Y坐标
 * 说明:
 *   该函数对DIB图像进行中值滤波。
 ************************************************************************/
#define iFilterW 1
#define iFilterH 1
#define iFilterMX 1
#define iFilterMY 1
#define WIDTHBYTES(bits)    (((bits) + 31) / 32 * 4)
unsigned char GetMedianNum(int * bArray, int iFilterLen);
void MedianFilter(unsigned char *pImg1,unsigned char *pImg,int nWidth,int nHeight)
{		
    unsigned char   *lpSrc;			                // 指向源图像的指针	
	unsigned char   *lpDst;		                 	// 指向要复制区域的指针
	int         aValue[iFilterH*iFilterW];		    // 指向滤波器数组的指针
	int			i,j,k,l;		                    // 循环变量	
	int			lLineBytes;		                    // 图像每行的字节数	
	lLineBytes = WIDTHBYTES(nWidth * 8);
	for ( i=0;i<nWidth;i++,pImg++ )
		(*pImg)=0;
	// 开始中值滤波
	// 行(除去边缘几行)
	for(i = iFilterMY; i < nHeight - iFilterH + iFilterMY + 1; i++)
	{
		// 列(除去边缘几列)
		for(j = iFilterMX; j < nWidth - iFilterW + iFilterMX + 1; j++)
		{
			// 指向新DIB第i行,第j个象素的指针
			lpDst = pImg + lLineBytes * (nHeight - 1 - i) + j;
			
			// 读取滤波器数组
			for (k = 0; k < iFilterH; k++)
			{
				for (l = 0; l < iFilterW; l++)
				{
					// 指向DIB第i - iFilterMY + k行,第j - iFilterMX + l个象素的指针
					lpSrc = pImg1 + lLineBytes * (nHeight - 1 - i + iFilterMY - k) + j - iFilterMX + l;
				
					// 保存象素值
					aValue[k * iFilterW + l] = *lpSrc;
				}
			}
			
			// 获取中值
			* lpDst = GetMedianNum(aValue, iFilterH * iFilterW);
		}
	}
}
unsigned char GetMedianNum(int * bArray, int iFilterLen)
{
	int		i,j;			// 循环变量
	unsigned char bTemp;
	
	// 用冒泡法对数组进行排序
	for (j = 0; j < iFilterLen - 1; j ++)
	{
		for (i = 0; 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;
}