表格识别的第一个关键步是二值法。
二值化算法包括全局二值化和局部二值化, 全局二值化具有速度快但效果相对差的特点, 局部二值化算法具有速度慢效果好的特点。
全局阈值
方法一:直接采用im2bw ;不断尝试阈值
阈值为240:
阈值为163:
阈值为10:
方法一虽然很简单,而且识别效果也不是很好,但是却是速度最快的方法。
更简便方法可以,直接求出直方图,根据直方图大概就能确定阈值。
方法二:迭代法求阈值(得到的全局阈值为187.329)
迭代式阈值选取的基本思路是:首先根据图像中物体的灰度分布情况,选取一个近似
阈值作为初始阈值,一个较好的方法就是将图像的灰度均值作为初始阈值;然后通过分
割图像和修改阈值的迭代过程获得认可的最佳阈值。迭代式阈值选取过程可描述如下。
(1)选取一个初始阈值T。
(2)利用阈值T把给定图像分割成两组图像,记为R1和R2 。
(3)计算R1和R2 均值u1和 u2
(4)选取新的阈值T,且T=(u1+u2)/2
(5)重复第(2)~(4)步,直至R1和R2均值不再变化为止。
具体实现时,首先根据初始开关函数将输入图逐个图像分为前景和背景,在第一遍
对图像扫描结束后,平均两个积分器的值以确定一个阈值。用这个阈值控制开关再次将
输入图分为前景和背景,并用做新的开关函数。如此反复迭带直到开关函数不在发生变
化,此时得到的前景和背景即为最终分割结果。迭代所得的阈值分割的图像效果良好。
基于迭代的阈值能区分出图像的前景和背景的主要区域所在,但在图像的细微处还没有
很好的区分度。对某些特定图像,微小数据的变化却会引起分割效果的巨大改变,两者
的数据只是稍有变化,但分割效果却反差极大。对于直方图双峰明显,谷底较深的图像,
迭代方法可以较快地获得满意结果,但是对于直方图双峰不明显,或图像目标和背景比
例差异悬殊,迭代法所选取的阈值不如其它方法。将全局平均值作为初始阈值,将图像分为两部分,求每部分的均值,迭代,直到这两部分均值不在变化。
方法三:居于最大类间差的方法----Otsu法
得到的全局阈值为186.88
图像记t为前景与背景的分割阈值,前景点数占图像比例为w0,平均灰度为u0;背
景点数占图像比例为w1,平均灰度为u1,则图像的总平均灰度为:u=w0*u0+w1*u1
从最小灰度值到最大灰度值遍历t,当t使得值
g=w0*(u0-u)^2+w1*(u1-u)^2
最大时t即为分割的最佳阈值。
大津法可作如下理解:该式实际上就是类间方差值,阈值t 分割出的前景和背景
两部分构成了整幅图像,而前景取值u0,概率为 w0,背景取值u1,概率为w1 ,总均值
为u,根据方差的定义即得该式。因方差是灰度分布均匀性的一种度量,方差值越大,说
明构成图像的两部分差别越大,当部分目标错分为背景或部分背景错分为目标都会导致
两部分差别变小,因此使类间方差最大的分割意味着错分概率最小。直接应用大津法计
算量较大,因此在实现时采用了等价的公式
g=w0*w1*(u0-u1)^2
第二,第三种方法得到的阈值相差不大,效果也类似,不能解决光照不均的局面。中间那块明显的在二值化后信息丢失了。这是因为用全局阈值是无法根据每个特定的区域采用不同的阈值,于是只能尝试采用局部阈值,或是对图像进行预处理改进其直方图特性。
局部阈值法
方法四:对图像分块,对每块采用方法三最大类间差的方法处理。(改进的地方分块的长宽不是一致的)
看上图,明显看到光照不均那段被检测出来了,但是缺点是要很好的设置好分块的大小。而且图片产生了伪影,多出了很多黑块。怎么会出现这些黑块呢?观察后发现黑块往往是在图像灰度细节不够丰富的区域产生。黑块产生的原因一定是出在每个分块采用的二值化方法--otsu算法。otsu算法更适合空间细节不丰富但灰度细节却很丰富的图像,因为这种图像往往才会有明显的类间距。对于灰度不丰富的图像,otsu 得到的阈值较不理想。
方法五:ernsen算法凭其优异的综合性能, 在局部二值化领域占有重要一席, 它较适合解决光照不均的问题。
这个算法的中心思想是:设当前像素为P,计算以P为中心的大小为(2w+1)*(2w+1)窗口内的所有像素的最大值M与最小值N,两者的均值T,if(M-N)> S 则当前点P的阈值为T。else当前窗口所在区域的灰度级差别较小,那么窗口在目标区或在背景区,若T>T1则当前点灰度值为255,否则,当前点灰度值为0。S设为15, T1设为20。(这两个值的设定还是需要根据具体的图像具体分析)
从上图中可以看到,8.9两行得到很好的处理,说明bernsen方法能够较为有效的解决光照不均的问题。美中不足的是这方法运行的时间太长,针对这一问题也有很多的改善的方法。
预处理改进其直方图特性
上述的方法只是单纯对图像进行二值化,没有去除噪声等步骤。硕士学位论文《表格识别预处理与表格字符提取算法研究》中提到了一种通过非线性对比度增强和用高斯型拉普拉斯算子对图像进行处理改变直方图的算法得到很好效果。算法的思想就是在二值化之前先通过亮度变化把增强图像的对比度,把原本属于背景的前景映射到前景来,然后用一个滤波器进一步增强。因为有了前面的基础,实现这个方法也比较容易。
从上图看到,进过预处理后图像的直方图特性得到改善。能够很容易将图像二值化。
二值化效果优于之前的方法,线段没有断裂。
附录程序:
程序一:预处理改进其直方图特性
clc;
clear all;
[fn pnfi]=uigetfile('*.jpg','choose a picture');
I=imread([pnfn]);
I=rgb2gray(I);
[m,n]=size(I);
figure;
subplot(3,1,1)
imhist(I);
%imshow(I);
I=double(I);
avg=mean(I(:));
mi=min(I(:));
p=0.45;
for i=1:m
for j=1:n
if I(i,j)>avg
I(i,j)=255;
else
I(i,j)=(255-abs((((I(i,j)-avg)^p)*255)/(avg-mi)^p));
end
end
end
mask=fspecial('log');
g=imfilter(I,mask,'replicate');
g=I-g;
% figure;
subplot(3,1,2)
% imshow(uint8(I));
% subplot(3,3,2)
imhist(uint8(I))
%g=imadjust(I,[],[],2);
%g=1./(1+(3./(double(I))).^20);
%subplot(3,3,3)
% figure;
subplot(3,1,3)
imhist(uint8(g))
%subplot(3,3,4)
%imshow(g);
g=im2uint8(g);
[t,re]=binary2(g);
%subplot(1,2,1);
%subplot(3,3,5)
figure;
imshow(re);
%subplot(1,2,2);
% figure;
%imshow(re);
程序二:迭代法
function[t b1 ] = binary2( f1 )
t=mean(f1(:));
is_done=false;
count=0;
while~is_done
r1=f1(f1<=t);
r2=f1(f1>t);
temp1=mean(r1(:));
if isnan(temp1);
temp1=0;
end
temp2=mean(r2(:));
if isnan(temp2)
temp2=0;
end
t_new=(temp1+temp2)/2;
is_done=abs(t_new-t)<1;
t=t_new;
count=count+1;
if count>=1000
Error='Error:Cannot find the idealthreshold.'
Return
end
end
b1=im2bw(mat2gray(f1),t/256);
end
程序三:otsu法
function[b1,reT] =binary_otus( f1 )
[rc]=size(f1);
gray_level=256;
resultT=0;
hist=zeros(gray_level,1);
fori=1:r
for j=1:c
hist(f1(i,j)+1)=hist(f1(i,j)+1)+1;
end
end
hist=hist/(r*c);
vmax=0;
fortt=1:gray_level
T=tt-1;
w0=0;w1=0;u0=0;u1=0;var=0;%重要的地方,在每次循环遍历的时候。要把涉及到的变量清零。
for i=1:T+1
w0=w0+hist(i);
u0=u0+(i-1)*hist(i);
end
u0=u0/w0;
w1=1-w0;
for j=T+2:gray_level
u1=u1+(j-1)*hist(j);
end
u1=u1/w1;
var=w0*w1*(u0-u1)^2;
% v(tt)=var;
if var>vmax
vmax=var;
resultT=T;
end
end
b1=im2bw(mat2gray(f1),resultT/255);
reT=resultT/255;
end
% fori=1:r
% forJ=1:c
% if f1(i,j)>rsultT
%b1(i,j)=1;
% else
%b1(i,j)=0;
% end
% end
% end
程序四:局部阈值otsu
function[ b1] = binary_part(gray_image,a,b)
[m,n]=size(gray_image);
result=zeros(m,n);
fori=1:a:m
for j=1:b:n
if((i+a)>m)&&((j+b)>n) %分块
block1=gray_image(i:end,j:end); %右下角区块
elseif((i+a)>m)&&((j+b)<=n)
block1=gray_image(i:end,j:j+b-1); %最右列区块
elseif((i+a)<=m)&&((j+b)>n)
block1=gray_image(i:i+a-1,j:end); %最下行区块
else
block1=gray_image(i:i+a-1,j:j+b-1);%普通区块
end
[ block,~]=binary_otus(block1);
if((i+a)>m)&&((j+b)>n) %合并结果
result(i:end,j:end)=block;
elseif((i+a)>m)&&((j+b)<=n)
result(i:end,j:j+b-1)=block;
elseif((i+a)<=m)&&((j+b)>n)
result(i:i+a-1,j:end)=block;
else
result(i:i+a-1,j:j+b-1)=block;
end
end
end
b1=result;
end
程序五:bernsen算法
function[ b1 ] = binary_bernsen( f1 )
[m,n]=size(f1);
s=15;
t1=20;
exI=uint8(ones(m+2,n+2));%扩展图片,预分配一个矩阵
re=uint8(ones(m,n));
exI(2:m+1,2:n+1)=f1;%把原图片赋给矩阵
%==========对矩阵进行填充==========%
exI(1,:)=exI(2,:);
exI(m+2,:)=exI(m+1,:);
exI(:,1)=exI(:,2);
exI(:,n+2)=exI(:,n+1);
fori=2:m+1
for j=2:n+1
%===========求3*3区域内的阈值并对图像进行二值化,结果存在re中==========%
ma=max(max(exI(i-1:i+1,j-1:j+1)));
mi=min(min(exI(i-1:i+1,j-1:j+1)));
t=(ma+mi)/2;
if ma-mi>s
if exI(i,j)>t
re(i-1,j-1)=255;
else
re(i-1,j-1)=0;
end
else
if t>t1
re(i-1,j-1)=255;
else
re(i-1,j-1)=0;
end
end
end
end
b1=re;
end