最近一直在研究图像分割技术,越研究觉得越有意思。这里所说的研究其实也只是研究别人论文然后自己实现一下而已罢了。。。
图像分割就是把图像中的各个部分分开,能区分出哪里是前景,哪里是背景,如果前景和背景分别用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);