(MATLAB/C/Python)快速中值滤波
(MATLAB/C/Python)快速中值濾波
- 一、中值濾波
- 二、快速中值濾波
- 介紹
- 原理
- 優(yōu)化
- 三、代碼
- MATLAB
- C
- Python
- 四、測試
- 其他
by HPC_ZY
最近一個項(xiàng)目中需要用到中值濾波(不能調(diào)庫),但是核半徑相當(dāng)大,用傳統(tǒng)的方法運(yùn)行速度極慢。因此查閱文獻(xiàn)找到快速中值濾波的方法。寫成三種語言并分享給大家。
一、中值濾波
簡單說就是,就是對某點(diǎn)鄰域內(nèi)所有像素進(jìn)行排序,取序數(shù)在中間的值替代原始值。
這樣做對脈沖噪聲有良好的濾除作用,特別是在濾除噪聲的同時,能夠保護(hù)信號的邊緣,使之不被模糊。
實(shí)現(xiàn)方法
step 1:通過從圖像中的某個采樣窗口取出奇數(shù)個像素進(jìn)行排序
step 2:用排序后的中值取代要處理的像素即可
代碼見后文。
注:本文主要講圖像處理,所有使用 “像素 ” 替代 “ 數(shù)據(jù)”。
二、快速中值濾波
介紹
中值濾波主要耗時就在于對窗口(鄰域)內(nèi)像素進(jìn)行排序,因此針對如何獲取中值進(jìn)行優(yōu)化。
最初——經(jīng)典的中值濾波對窗口內(nèi)所有像素進(jìn)行排序,所以排序算法的選擇就很重要。
接著——但后來有人意識到 “我們只需要中間值”,沒必要將整個序列進(jìn)行排序,因此出現(xiàn)了一些快速搜索數(shù)組中間值的方法。
然后——由于圖像的像素值為0~255的整數(shù),1979年有人就提出了用累積直方圖尋找中值的方法。
最后——人們又在這基礎(chǔ)上不斷改進(jìn)。
本文主要講基于直方圖的快速中值濾波方法
原理
step 1:統(tǒng)計(jì)N?NN*NN?N窗口內(nèi)像素
step 2:計(jì)算累積直方圖
step 3:找到累積直方圖值剛好超過N?N2\frac{N*N}{2}2N?N?時對應(yīng)的灰度值。
通過一個簡單的例子更直觀的說明。
這里假設(shè)一個只有8個灰度級的圖像,某個5?55*55?5的窗口內(nèi)值如下,
[0455534765677763211001100]\begin{bmatrix} 0 &4 &5&5&5 \\ 3 & 4&7&6&5\\6&7&7&7&6\\3&2&1&1&0\\0&1&1&0&0 \end{bmatrix} ???????03630?44721?57711?56710?55600????????
其統(tǒng)計(jì)直方圖如下表。對于5*5的窗口,中值的序數(shù)為13,所以參照累積直方圖能快速中值為4。
這里我們可以發(fā)現(xiàn),其實(shí)并不需要算出整個累積直方圖,只要某一次計(jì)算超過半數(shù),就可以停止了。
| 直方圖 | 5 | 4 | 1 | 2 | 2 | 4 | 3 | 4 |
| 累積直方圖 | 5 | 9 | 10 | 12 | 14 | 18 | 21 | 25 |
直方圖方法中,對于圖像灰度級為LLL、窗口尺寸為N?NN*NN?N,我們只需要進(jìn)行以下操作:
1)進(jìn)行N?NN*NN?N次統(tǒng)計(jì)(獲得直方圖)
2)最多進(jìn)行L?1L-1L?1次累加+判斷(計(jì)算累積直方圖的同時判斷是否超過半數(shù))
通常圖像的LLL都為256,我們可以推斷對于3?33*33?3的窗口,傳統(tǒng)排序方法速度更快;但當(dāng)N越來越大,直方圖法的優(yōu)勢就越來越大。
代碼見后文
優(yōu)化
進(jìn)一步思考可以發(fā)現(xiàn),我們在平移窗口時,新窗口里有N?(N?1)N*(N-1)N?(N?1)的像素都是上一窗口里有的(如下圖黃色),如果重新統(tǒng)計(jì)就浪費(fèi)時間。
所以有人提出不必重新計(jì)算直方圖,只用更新直方圖——移除(如下圖紅色)+加入(如下圖綠色)。
代碼見后文
三、代碼
本文首先用MATLAB講解演示:傳統(tǒng)排序中值法,快速直方圖中值法,改進(jìn)快速直方圖法
然后直接分享C、Python的改進(jìn)快速直方圖法。
MATLAB
為了方便轉(zhuǎn)為C語言,沒有使用MATLAB的函數(shù)
當(dāng)然了,MATLAB有他自帶的中值濾波,賊快
C
改進(jìn)(更新)直方圖方法
/*** 中值濾波 ***/ void medfilter2(BYTE* pImgOut, // (out)濾波后圖像(0~255)const BYTE* pImg, // (in)原始灰度圖像(0~255)int imgWidth, // (in)圖像寬(pixel)int imgHeight, // (in)圖像高(pixel)int nR // (in)窗口核半徑(pixel) ) {int nL = 2 * nR + 1;int num = nL*nL;int cidx = num / 2 + 1; // 中值所在的位置// 初始化統(tǒng)計(jì)直方圖int *hist = (int*)malloc(256 * sizeof(int));// 開始遍歷int tmp = 0;for (int i = nR; i < imgHeight - nR; i++){memset(hist, 0, 256 * sizeof(int));// 第一列for (int m = -nR; m <= nR; m++){for (int n = -nR; n <= nR; n++){tmp = pImg[(i + m)*imgWidth + (nR + n)];hist[tmp]++;}}int histsum = 0;for (int k = 0; k < 256; k++){histsum += hist[k];if (histsum >= cidx){pImgOut[i*imgWidth + nR] = k;break;}}// 計(jì)算后續(xù)for (int j = 1 + nR; j < imgWidth - nR; j++){for (int m = -nR; m <= nR; m++){tmp = pImg[(i + m)*imgWidth + (j - 1 - nR)];hist[tmp]--;tmp = pImg[(i + m)*imgWidth + (j + nR)];hist[tmp]++;}int histsum = 0;for (int k = 0; k < 256; k++){histsum += hist[k];if (histsum >= cidx){pImgOut[i*imgWidth + j] = k;break;}}}}}Python
寫時候遇到一個小問題,由于本人剛?cè)腴T不久,不太懂底層的原理。
用python跑for循環(huán)的時候運(yùn)行速度特別慢,如果有大佬知道原因希望留言告訴我,謝謝了。
代碼還是放在這里。
四、測試
這里只展示matlab測試結(jié)果,
clear; close all; clc% 制造含噪圖像 im = imread('test.jpg'); gray = rgb2gray(im); in = imnoise(gray,'salt & pepper',0.02); % 椒鹽噪聲r = 4;% MATLAB自帶函數(shù) tic out0 = medfilt2(in,[2*r+1,2*r+1]); toc% 經(jīng)典排序方法 tic out2 = medianfilterC(in,r); toc% 直方圖中值法 tic out3 = medianfilterCHist(in,r); toc% 改進(jìn)直方圖中值法 tic out4 = medianfilterCHistUpdata(in,r); toc結(jié)果如下圖,由于我寫的沒有處理邊緣的像素,所以結(jié)果有黑邊。這里使用半徑為4,如果更大效果就非常明顯了。
其他
《A Fast Two-Dimensional Median Filtering Algorithm》
《Median Filter in Constant Time》
《Fast Median Filtering by Use of Fast Localization of Median Value》
總結(jié)
以上是生活随笔為你收集整理的(MATLAB/C/Python)快速中值滤波的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: GE Historian9.0服务器安装
- 下一篇: python 二维相关系数计算