最近一直在研究圖像分割技術,越研究覺得越有意思。這里所說的研究其實也只是研究別人論文然后自己實現一下而已罷了。。。
圖像分割就是把圖像中的各個部分分開,能區分出哪里是前景,哪里是背景,如果前景和背景分別用0和1表示,那就是叫做圖像二值化了。但是圖像分割也不僅僅限於二分,可以任意多的分。從這個角度講二值化是圖像分割結果的一種表示而已,只不過二分研究的比較多,也比較容易些。
至於分割的方法有很多種,比較粗的分類可以分為全局和局部的。全局方法就是一個閾值,像素值大於此值的為1,小於此值的為0。局部方法就是對每一個像素求閾值。Niblack方法就是局部方法中的一種,它根據以像素點為中心的鄰域內的點的情況為此像素計算閾值。下面是每個像素閾值的計算公式,m是均值,s是標准差。
看起來還是比較簡單的,下面是實現這個算法的matlab代碼:
function g=segNiBlack(f,w2,k) % segmentation method using Niblack thresholding method % input: w2 is the half width of the window w = 2*w2 + 1; window = ones(w, w); % compute sum of pixels in WxW window sp = conv2(f, window, 'same'); % convert to mean n = w^2; % number of pixels in window m = sp / n; % compute the std if k ~= 0 % compute sum of pixels squared in WxW window sp2 = conv2(f.^2, window, 'same'); % convert to std var = (n*sp2 - sp.^2) / n / (n-1); s = sqrt(var); % compute Niblack threshold t = m + k * s; else t = m; end g=f<t; end
函數的輸入f是要二值化的圖像,w2是窗口大小的一半,k就是系數。代碼里面的conv2是卷積,將圖像矩陣與全1矩陣做卷積,其實就是再求這個窗口內像素的和。這樣做速度比較快,比一個像素一個像素的遍歷速度快10多倍。
Niblack還算是一種比較常用的二值化算法,算法簡明,速度較快,效果也不錯,經常用在文本圖像的文字與背景分割中。下面就拿我用手機照紙上的一些文字,測試一下。
左:用手機照的一篇打印的論文中的文字 右:用Niblack算法進行文本分離的結果
可以看到背景有些噪點,文字有些地方連了起來,但是整體效果還不錯,為了取得更好的結果,通常預處理和后續處理是必不可少的環節。看起來有點模糊的是因為圖片太大為了放到文章里我給它縮小了一下。
代碼和參數如下:
tf=imread('http://www.cnblogs.com/mydb/tests/paperwords.jpg');
tf=rgb2gray(tf);
tf=double(tf);
tf=medfilt2(tf,[5,5]);
gb2=segNiBlack(tf,32,0.01);
gb2=medfilt2(gb2,[7,7]);
figure();imshow(gb2);