中值滤波算法以某像素的领域图像区域中的像素值的排序为基础,将像素领域内灰度的中值代替该像素的值[1];
如:以3*3的领域为例求中值滤波中像素5的值
图1
1)int pixel[9]中存储像素1,像素2...像素9的值;
2)对数组pixel[9]进行排序操作;
3)像素5的值即为数组pixel[9]的中值pixel[4]。
中值滤波对处理椒盐噪声非常有效。
二 中值滤波代码实现
项目工程:https://github.com/ranjiewwen/Everyday_Practice/tree/master/MedianFilter/MedianFilter/MedianFilter
//中值滤波:本算法采用3*3的领域范围 void MyImage::MedianFilterOper() { //0. 准备:获取图片的宽,高和像素信息, int const num = 3 * 3; unsigned char pixel[num] = { 0 }; //保存领域的像素值 int width = m_bmpInfo.biWidth; int height = m_bmpInfo.biHeight; int widthbyte = (width * m_bmpInfo.biBitCount / 8 + 3) / 4 * 4; //保证为4的倍数 //相对于中心点,3*3领域中的点需要偏移的位置 int delta[3 * 3][2] = { { -1, -1 }, { -1, 0 }, { -1, 1 }, { 0, -1 }, { 0, 0 }, { 0, 1 }, { 1, -1 }, { 1, 0 }, {1, 1} }; //1. 中值滤波,没有考虑边缘 for (int i = 1; i < height-1; ++i) { for (int j = 1; j < widthbyte-1; ++j) { //1.1 提取领域值 for (int k = 0; k < num; ++k) { pixel[k] = m_imagedata[(i + delta[k][0])*widthbyte + j + delta[k][1]]; } //1.2 排序 qsort(pixel, num, sizeof(unsigned char), compa); //1.3 获取该中心点的值 m_imagedata[i*widthbyte + j] = pixel[num / 2]; } } }
3 中值滤波概述
中值滤波是基于排序统计理论的一种能有效抑制噪声的非线性信号平滑处理技术,它将每一像素点的灰度值设置为该点某邻域窗口内的所有像素点灰度值的中值。
中值滤波的基本原理是把数字图像或数字序列中一点的值用该点的一个邻域中各点值的中值代替,让周围的像素值接近的真实值,从而消除孤立的噪声点。方法是用某种结构的二维滑动模板,将板内像素按照像素值的大小进行排序,生成单调上升(或下降)的为二维数据序列。二维中值滤波输出为g(x,y)=med{f(x-k,y-l),(k,l∈W)} ,其中,f(x,y),g(x,y)分别为原始图像和处理后图像。W为二维模板,通常为3*3,5*5区域,也可以是不同的的形状,如线状,圆形,十字形,圆环形等。
4 中值滤波算法原理
中值滤波数学实现:对一个数字信号序列xj(-∞<j<∞)进行滤波处理时,首先要定义一个长度为奇数的L长窗口,L=2N+1,N为正整数。设在某一个时刻,窗口内的信号样本为x(i-N),…,x(i),…,x(i+N),其中x(i)为位于窗口中心的信号样本值。对这L个信号样本值按从小到大的顺序排列后,其中值,在i处的样值,便定义为中值滤波的输出值。
在实际应用中,随着所选用窗口长度的增加,滤波的计算量将会迅速增加。因此,寻求中值滤波的快速算法,是中值滤波理论的一个重要研究内容。中值滤波的快速算法,一般采用下述三种方式:①直方图数据修正法;②样本值二进制表示逻辑判断法;③数字和模拟的选择网络法。
对中值滤波的理论研究,还集中于统计特性分析和根序列的描述方面。当一个信号序列经一特定窗口长度的中值滤波反复处理后,它会收敛于某一个不再变化的序列,这个序列称为中值滤波的根序列。根序列是描述中值滤波特性的一个重要概念。通过对根序列结构的研究,可以确定原信号序列中,哪些成分可以经中值滤波后保留下来,哪些成分将被抑制。这对确定中值滤波器的窗口长度,提供了重要依据。用VLSI实现的中值滤波器芯片,可供实时处理中应用。
// zhongzhilvbo.cpp : 定义控制台应用程序的入口点。 // #include <stdio.h> #include <math.h> #include <memory.h> #include <conio.h> #include <stdlib.h> #include <windows.h> #include "stdafx.h" //原图象的宽度和高度 #define width 352 #define higth 288 int lvbo(unsigned char D[9]) //冒泡排序 { unsigned int temp; int i,j; for(i=0;i<9;i++) { for(j=0;j<9-i;j++) { if(D[i]>D[j+1]) { temp=D[i]; D[i]=D[j+1]; D[j+1]=temp; } } } return D[4]; } void main() { FILE *fp,*newfp; int i,j; if(!(fp=fopen("fmh1.bmp","rb"))) { printf("Open file %s error! ","k.bmp"); return ; } if(!(newfp=fopen("fmout.bmp","wb"))) { printf("Open file %s error! ","result.bmp"); return ; } unsigned char buffer[54+1024];//定义原图像头缓冲区 fread(buffer,1,54+1024,fp);//读取文件头54个字节 unsigned long length=width*higth;//图像的总象素个数 unsigned char readData[higth][width]; //用于存储原图数据的数组 unsigned char writeData[higth][width]; //用于存储原图数据的数组 fread(&readData[0][0], sizeof(unsigned char),length, fp);//从原图读入数据 for(i=0;i<higth;i++) { for(j=0;j<width;j++) { writeData[i][j]=readData[i][j]; } } unsigned char D[9]; //定义选取框 for(i=1;i<higth-1;i++) { for(j=1;j<width-1;j++) { D[0]=readData[i-1][j+1]; D[1]=readData[i][j+1]; D[2]=readData[i+1][j+1]; D[3]=readData[i-1][j]; D[4]=readData[i][j]; D[5]=readData[i+1][j]; D[6]=readData[i-1][j-1]; D[7]=readData[i][j-1]; D[8]=readData[i+1][j-1]; writeData[i][j]=lvbo(D); } } fwrite(buffer,sizeof(unsigned char),54+1024,newfp); fwrite(writeData,sizeof(unsigned char),length,newfp); fclose(newfp); fclose(fp); return ; }
参考:http://www.cnblogs.com/tanfy/p/median_filter.html
http://www.cnblogs.com/qiqibaby/p/5281743.html