中值滤波是对一个滑动窗口内的诸像素灰度值排序,用其中值代替窗口中心象素的原来灰度值,它是一种非线性的图像平滑法,它对脉冲干扰级椒盐噪声的抑制效果好,在抑制随机噪声的同时能有效保护边缘少受模糊。
中值滤波可以过滤尖峰脉冲。目的在于我们对于滤波后的数据更感兴趣。滤波后的数据保留的原图像的变化趋势,同时去除了尖峰脉冲对分析造成的影响。
以一维信号的中值滤波举例。对灰度序列 80、120、90、200、100、110、70,如果按大小顺序排列,其结果为 70、80、90、10O、110、120、200,其中间位置上的灰度值为 10O,则该灰度序列的中值即为 100。一维信号中值滤波实际上就是用中值代替规定位置(一般指原始信号序列中心位置)的信号值。对前面所举的序列而言,中值滤波的结果是用中值 100 替代序列 80、120、90、200、100、110、70 中的信号序列中心位置值 200,得到的滤波序列就是 80、120、90、100、100、110、70。如果在此序列中 200 是一个噪声信号,则用此方法即可去除这个噪声点。
二维中值滤波是:对于一幅图像的象素矩阵,取以目标象素为中心的一个子矩阵窗口,这个窗口可以是 3*3 ,5*5 等根据需要选取,对窗口内的象素灰度排序,取中间一个值作为目标象素的新灰度值。窗口示例如 ooooxoooo 上面 x 为目标象素,和周围 o 组成 3*3 矩阵 Array,然后对这 9 个元素的灰度进行排序,以排序后的中间元素 Array[4] 为 x 的新灰度值,如此就完成对象素 x 的中值滤波,再迭代对其他需要的象素进行滤波即可。
图像处理中,中值滤波的实现方法
1:通过从中的某个采样窗口取出奇数个数据进行排序 2:用排序后的取代要处理的数据即可 中值滤波的算法实现过程,重点是排序,最常用的冒泡排序~~ 把滤波区间的数据从小到大进行排序,然后取中值,(如果是奇数个数据,那么中值就只有一个了,如果偶数个数据,中值有两个,可以对两个数据再求平均)下面是一个 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 < 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;
- }
下面是一个完整的 C 语言程序,用在图像处理中
- 注:bArray是一个整形指针,我们传入的一般是一个数组,用来存储待排序的数据iFilterLen是滤波器的长度用在图像处理中时,由于像素的取值范围是0~255,刚好是unsigned char的范围,所以函数的返回值是unsigned char,如果我们要处理的数是float型,或其他类型,返回值也可以更改~~返回值是bTemp,也即是我们想得到的中值
- /*************************************************************************
- * 函数名称:
- * 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 < 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;
- }
来源: http://www.bubuko.com/infodetail-1858033.html