中值濾波是一種典型的非線性濾波技術。它在一定條件下可以克服線性濾波器如最小均方濾波,均值濾波等帶來的圖像細節模糊,而且對濾波脈沖干擾及圖像掃描噪聲非常有效。
傳統的中值濾波一般采用含有奇數個點的滑動窗口,用窗口中各點灰度值的中值來替代指定點的灰度值。對於奇數個元素,中值為大小排序后中間的數值;對於偶數個元素,中值為排序后中間兩個元素灰度值的平均值。
中值濾波是一種典型的低通濾波器,主要用來抑制脈沖噪聲,它能徹底濾除尖波干擾噪聲,同時又具有能較好地保護目標圖像邊緣的特點。
標准一維中值濾波器的定義為:
yk = med{ xK-N, xk-N+1, ... ,xk, ... ,xK+N }
式中,med表示取中值操作。中值濾波的濾波方法是對滑動濾波窗口(2N+1)內的像素做大小排序,濾波結果的輸出像素值規定為該序列的中值。
二維中值濾波的窗口形狀和尺寸設計對濾波的效果影響較大,不同的圖像內容和不同的應用要求,往往采用不同的形狀和尺寸。常用的二維中值濾波窗口有線狀,方形,圓形,十字形及圓環形等,窗口尺寸一般選為3。當然也可以采用其他尺寸,主要視具體情況而定。
1.中值的計算關鍵在於對滑動窗口內的像素進行排序,排序算法的選擇是影響中值濾波算法的重要因素。傳統的排序算法是基於冒泡排序法,若窗口中的像素為m,則每個窗口排序需要m(m-2)/2次像素的比較操作,時間復雜度為O(m2)。此外常規的濾波算法每移動一次窗口就要進行一次排序。當一幅圖像的大小為NXN時,則整個計算需要O(m2N2)時間,當窗口較大時,計算量很大,較費時。
2.為了提高中值濾波的實現速度,針對3X3中值濾波,介紹一種快速的並行中值濾波方法。下圖為3X3窗口內像素排列
首先對窗口內的每一列分別計算最大值,中值和最小值,這樣就得到了3組數據
最大值組:Max0 = max[P0,P3,P6],Max1 = max[P1,P4,P7],Max2 = max[P2,P5,P8]
中值組: Med0 = med[P0,P3,P6],Med1 = med[P1,P4,P7], Med2 = med[P2,P5,P8]
最小值組:Min0 = Min[P0,P3,P6],Min1 = Min[P1,P4,P7],Min2 = max[P2,P5,P8]
由此可以看到,最大值組中的最大值與最小值組中的最小值一定是9個元素中的最大值和最小值,不可能為中值,剩下7個;中值組中的最大值至少大於5個像素,中值組中的最小值至少小於5個像素,不可能為中值,剩下5個;最大值組中的中值至少大於5個元素,最小值組中的中值至少小於5個元素,不可能為中值,最后剩下3個要比較的元素,即
最大值組中的最小值Maxmin,中值組中的中值Medmed,最小值組中的最大值MinMax;找出這三個值中的中值為9個元素的中值。
算法實現:

/********************************************************************** * * 函數名稱: * MedFilter(int FilterH, int FilterW, int FilterCX, int FilterCY) * * 參數: * int FilterH 模板的高度 * int FilterW 模板的寬度 * int FilterCX 模板的中心元素X坐標 ( < FilterW - 1) * int FilterCY 模板的中心元素Y坐標 ( < FilterH - 1) * * 返回值: * void * * 說明: * 中值濾波的算法 * **********************************************************************/ void CImgEnhance::MedianFilter(int FilterH, int FilterW, int FilterCX, int FilterCY) { unsigned char* pSrc; unsigned char* pDst; int i,j,k,l; unsigned char* value; //指向濾波器數組的指針 if(m_pImgDataOut != NULL) { delete []m_pImgDataOut; m_pImgDataOut = NULL; } //計算圖像每行的字節數 int lineByte = (m_imgWidth * m_nBitCount / 8 + 3) / 4 * 4; if(m_nBitCount != 8) { AfxMessageBox("只能處理8位灰度圖像!"); return ; } //分配內存,以保存新圖像 m_nBitCountOut = m_nBitCount; int lineByteOut = (m_imgWidth * m_nBitCountOut / 8 + 3) / 4 * 4; if (!m_pImgDataOut) { //為處理后的圖像分配內存空間 m_pImgDataOut = new unsigned char[lineByteOut * m_imgHeight]; } int pixelByte = m_nBitCountOut / 8; for(i = 0; i < m_imgHeight; i++){ for(j = 0; j < m_imgWidth * pixelByte; j++) *(m_pImgDataOut + i * lineByteOut +j) = *(m_pImgData + i * lineByteOut + j); } //暫時分配內存,以保存濾波器數組 value = new unsigned char[FilterH * FilterW]; for (i = FilterCY; i < m_imgHeight - FilterH ; i++)//+ FilterCY + 1 { for (j = FilterCX; j < m_imgWidth - FilterW ; j++)//+ FilterCX + 1 { pDst = m_pImgDataOut + lineByte * (m_imgHeight - 1 - i) + j; for (k = 0; k < FilterH; k++) { for (l = 0; l < FilterW; l++) { pSrc = m_pImgData + lineByte * (m_imgHeight - l - i + FilterCY - k) + j - FilterCX + l; value[k * FilterW + l] = *pSrc; } } *pDst = FindMedianValue(value,FilterW * FilterH); } } }