上式中T为阈值,为了得到理想的二值图像,一般采用阈值分割技术,它对物体与背景有较强对比的图像的分割特别有效,它计算简单而且总能用封闭、连通的边界定义不交叠的区域。
2.2.1全局阈值分割法
对于比较简单的图像,可以假定物体和背景分别处于不同的灰度级,图像被零均值高斯噪声污染,所以图像的灰度分布曲线近似认为是由两个正态分布函数
和
叠加而成,图像的直方图将会出现两个分离的峰值。
对于这样的图像,分割阈值可以选择直方图的两个波峰间的波谷所对应的灰度值作为分割阈值。
图2.2较为简单的名片图2.3图像的灰度值分布曲线
对于一幅图像,设当前景与背景的分割阈值为t时,前景点占图像比例为w0,均值为u0,背景点占图像比例为w1,均值为u1。
则整个图像的均值为u=w0*u0+w1*u1。
建立目标函数g(t)=w0*(u0-u)^2+w1*(u1-u)^2,g(t)就是当分割阈值为t时的类间方差表达式。
Otsu算法使得g(t)取得全局最大值,当g(t)为最大时所对应的t称为最佳阈值。
Otsu算法又称为最大类间方差法。
图2.4Otsu算法处理前后的图像
2.2.2局部阈值分割法
局部阈值分割是采用局部区域内阈值的自适应的选择方法,来减少整体阈值对于局部特征的影响,更有利于对图片细节的展示。
其主要算法思想是:
首先以像素点(x,y)为中心,确定一个2w+1的窗口,然后通过计算该窗口内的最大值以及最小值的平均值来确定该窗口内的阈值,进而对该像素进行二值化处理。
由于局部阈值法是根据图片局部信息进行图片的灰度化,因此二值化信息丢失较少,但是会产生比较大的噪声的影响。
图2.5原图图2.6局部阈值算法处理前后的图像
2.2.3采用的分割方法
比较这两种算法发现,局部阈值法对于图像的前景的还原效果较好,但是产生的噪声比较多,并且由于其计算量比较大,所以算法时间消耗比较大,耗时比较长。
并且由于通常名片的拍摄是在室内环境下进行,一般不会产生光照不均的问题,考虑到计算速度等问题,本文采用OSTU方法对名片进行二值化处理。
2.3图像去噪
使用方法为:
中值滤波。
图2.5没有进行去噪图2.6进行去噪之后
2.4倾斜矫正
由于有时候相机、手机的拍摄角度没有固定,或名片的放置位置没有调整好的情况下,拍摄出来的名片图像存在一定的角度,如果不对图像倾斜进行矫正就影响到后面字符分割和识别,因此,对图像进行正确的倾斜矫正并在此基础上才能进行相应的正确版面分析,字符连通体几何特征提取等,这样才能在很大程度上保证OCR系统的工作性能,所以必须对名片图像进行角度倾斜。
基于Hough变换的方法:
首先对二值化得到的图像进行边缘检测,然后利用Hough变换将这些点拟合成若干直线。
由于一般拍摄名片的时候主要内容便是名片,所以,最长的直线是名片的长边,因此我们寻找到图片内最长的直线,即可计算出图片倾斜的角度,最后根据该角度旋转图片。
图2.7Hough变换前后对比
第三章版面分割
3.1版面分割概述
版面分割要能提取出下一步用于字符分割和识别的有用文本块,属于字符识别的预处理过程,也是后续的版面块筛选的必要条件。
所以正确的版面分析在名片识别系统中具有非常重要的地位。
这里综合使用了投影法和基于膨胀运算的连通域法对名片进行版面分割,投影法实现对名片的版面信息粗划分,基于膨胀运算的连通域法对分割的得到的版面信息进行细划分,得到相应的文字块。
流程图如图3.1所示。
图3.1版面分割流程图
3.2版面分割
3.2.1基于投影法的版面粗划分
投影是最基础的“自顶向下”的方法。
任意一幅图像都是由最基本的像素点组成的,经过预处理后是二值图像,图片上的文字信息部分是黑色像素点为0,取反后,文字等信息为1,经过行列投影,设置行列投影阈值,就可以对版块进行粗分割。
图3.2是一张名片图像的行投影处理后的示意图。
图3.2名片行处理的效果图
图3.3是以图3.2(c)中一张行处理后的版块进行列投影处理后的示意图。
图3.3图像块列处理的效果图
3.2.2基于膨胀运算的连通域搜索法
针对3.2.1使用投影法对名片的粗分割得到的版块信息,本文对名片图像文本块的精提取采用的是一种基于膨胀算法的连通域搜索法。
如果直接对文本图像进行连通区域的提取,这样的连通域提取是基于像素的,这样我们提取的连通域会非常多,而且非常小,然后再根据字内部的间距、字间距、行间距等特性对它们进行合并,以形成大的连通区域。
这样的过程会比较复杂,计算量大,速度慢。
所以,在名片图像块分割之前,我们首先对其进行膨胀处理,将相邻的字词,句子,以及属于同一段落的相邻行连接起来,以形成相对独立且大的连通单元,这样进行下一步分割工作的时候就比较方便。
膨胀的算符为⊕,A用B来膨胀写作A⊕B,其定义为:
A⊕B={x|{(B)x∩A}≠Ø}
根据上式可以将B看作一个卷积模板,膨胀就是先对B作关于原点的映射,再将映射连续地在A上移动而实现的。
3.2.2.1选取膨胀模块,并对图像进行膨胀运算
膨胀模块的选取还是依赖于文档图像自身的一些特征,如字符间的间隔,文本行、段之间的间隔,各个属性块(如文本块、图像块、表格块等等)之间的间隔,以及它们之间间隔的大小顺序等特征。
这个算法就是把名片图像进行膨胀后,再来提取基本连通域,膨胀主要是图片膨胀尺度的选择,这里由于图片的文字块是按行分布的,所以纵向膨胀尺度为零,横向的膨胀尺度是基于图片的列投影进行聚类选择的,图3.4是对3.2.1提取得到图像块的膨胀效果图。
图3.4图像块膨胀效果图
3.2.2.2膨胀尺寸的选择
决定膨胀尺寸的文本图像特征有字符间距、行间距、段间距等等,这时候就产生了一个阈值选择的问题,通过图像的列投影可以得到很多间距。
我们可以用聚类的方法来决定膨胀尺寸的选择,一般用K-均值聚类法。
K-均值聚类法要求各类样本到聚类中心的距离平方和最小,这种方法是建立在误差平方和准则的基础上的。
具体步骤如下:
例如对样本集:
●任选K个初始聚类中心、、…;
●将样本集中的样本按照最小距离原则分配到K个聚类中心,形成K个类群,即在第m次迭代时,若:
则,,其中是第m次迭代时,第j个聚类中心所代表的聚类域;
●根据第二步计算出的新聚类中心:
其中为第i个聚类域;
●如果所有的新的新的聚类中心与之前的聚类中心相同则停止算法,得到相应的聚类中心,否则转到第二步.
由于图像块中,主要是文字间距和行间距,故只需设置两个聚类中心,聚类后得到的小的值即图像块的文字间距,用于设置水平的膨胀尺度。
3.2.2.3提取出较小的连通区域
对名片图像进行膨胀运算后,属于同一区域的像素点,小连通区域大多粘连起来,形成大连通单元,然后再进行连通域的提取,运用边缘检测[]的方法来进行,每个单元都可以用一个闭合的曲线表示。
接着采用一个n*n大小的模板对经过边缘提取出的区域进行涂抹,如果该区域小于所设模板,就认为该区域为一个小连通域,需要进行合并。
n*n大小的模板可以根据实际需要选取,比如在对中文文本图像的分析中,此模板就可以取为一个文档中汉字的大小。
3.2.2.4搜索大的连通域,对小的连通域进行合并
经过第二步之后,获得了图像中比较小的连通区域,可以用最优路径搜索法,采用宽度优先的算法,并以“四邻域”搜索出较大的连通域,通过得到较大连通域完成小连通域的合并。
搜索较大连通域的算法如下:
1以左上角小连通域为初始区域S建立搜索图G,并把S放到O的未扩展表中。
2构建一个P的已扩展表,初始化为空。
3若O为空表则退出。
4选择O表中的第一个区域,移出放进P中,记此区域为N。
5搜索区域N的所有邻域,若没有转向第3步。
6把区域N的所有领域放到O表的末端,然后转向第4步。
将小连通域合并和的大连通域和原本的大连通域组成新的大连通域进行后续的处理。
3.2.2.5获得完整的大连通域并判断是否进一步融合
取版面中的矩形连通区域Ri为四元组:
Ri=(X11,Y11,X12,Y12)其中,(X11,Y11),(X12,Y12)分别为矩形区域Ri的左上角、右上角坐标。
比较这个区域中的所有小连通域的左上角和右下角的坐标,在比较的结果中,取最小的坐标值作为大连通区域的左上角坐标(X11,Y11),最大的坐标值作为大连通区域的右下角的坐标值(X12,Y12),记录下这块大连通区域的坐标,大连通域进一步合并的条件:
记两个不同的连通域
合并情况:
1、
且
有重叠。
2、
且
,
包含在
中。
3、
,间距太小。
3.3版面提取结果
图3.5图像块分割效果图
第四章Tesseract-OCR引擎的安装及结果演示
4.1Tesseract-OCR引擎的多语言支持特性
早期的Tesseract设计只对拉丁字符进行识别,随着对ocr技术的多语言识别的需求不断提高,Tesseract也增加了对多种语言的支持。
相比于拉丁字符仅由几十个字符组成,中文、日文、韩文等汉字或者由汉字衍生的文字,包括了数千种不同的字符形状,导致字符匹配的难度大大增加。
同时,类似于阿拉伯文的印刷体也往往是将文字连在一起的,会给字符分割增加很大的难度。
因此由于不同语言的文字板式、形态的差异性,对它们的识别处理也是要有所区别的。
相比于试图去找到一种适应所有语言的识别方法,对一种或几种指定的语言进行识别更具可行性。
针对不同类型的语言,tesseract提供了独立的字库支持,在最新的3.02版本中,包含了多达60多种不同语言的字库,用户可以任意的选择所需的字库进行组合。
4.2Tesseract-OCR引擎的配置
首先对于没有安装过tesseract的电脑,想要运行程序,需要一些系统变量的修改。
解压tess文件夹,解压后结果如图4.1
在计算机->属性->高级系统设置->高级->环境变量->系统变量中,在Path变量中加入包含文件
与
这两个文件的文件夹lib的路径。
如图4.2
图4.2
新建一个变量叫TESSDATA_PREFIX,将值设为本文件夹tess目录,如图4.3
图4.3
由于这一部分是用VS2010编程实现的,而本课题的主要代码是用MATLAB实现的,要做的就是在MATLAB中调C程序。
实现的方法具体来说就是在VS2010编译运行后会在Debug目录下生成一个.exe文件,然后在MATLAB中使用system()命令来调用这个.exe文件。
tess文件夹下的tess.exe就是这个文件(如果直接打开它,会显示参数数目有误,因为它要求有两个参数的输入),在matlab中使用方法如下
第一个参数,F:
\名片识别\test\test\Debug\test.exe是test.exe的路径
第二个参数,D:
\\image\\是图片文件夹放的位置,自动检测文件夹下的所有图片,要求都是.jpg格式,注意由于后两个参数是要传入C语言的,需要两个“\”用来转置。
第三个参数,D:
\\image\\是输出文件的位置,会生成一个result.txt文件,就是将所有图片的识别结果放到一个文本文件里面。
附录中提供test.cpp的源代码,可供参考。
4.3基于Tesseract-OCR引擎的名片识别结果演示
4.3.1名片1
4.3.2名片2
附录:
1.1主程序Matlab源代码:
img=imread('D:
\image\image\QQ11.jpg');
grayImg=rgb2gray(img);
BW=funIm2bw(img);%二值化函数
I0=funRotate(BW);%图像旋转函数
B=document_analysis(I0,grayImg);%版面分割函数
system('d:
\testNew.exed:
\\image\\d:
\\image\\');%调用tesseract.exe识别
2.1二值化处理Matlab源代码
functionim=funIm2bw(image)
%函数功能:
将输入的image图像进行二值化处理(大津阈值法)
%输出:
二值化后的二值图像
gray=rgb2gray(image);
gray=255-gray;
[m,n]=size(gray);
level=graythresh(gray);
im=im2bw(gray,level);%大津阈值法
2.2局部二值化算法核心函数
functionthreath=localThreathhold(image,centerX,centerY,w)
%输入参数:
image输入图像(灰度图像),
%ij分别为处理像素的横纵坐标
%w为局部阈值处理的窗口大小
%输出参数:
返回处理后该点的结果
%函数作用:
局部阈值化处理进行二值化,用于确定(centerX,centerY)像素点的二值化值确
local=image(centerX,centerY);
[mn]=size(image);
pix=zeros(1,w*w);%用于存放需要的处理数据用于后面的寻找最大值最小值
pixNum=1;
xl=centerX-w;xr=centerX+w;yl=centerY-w;yr=centerY+w;
isOver=0;
ifxl<=0
isOver=1;
elseifxr>m
isOver=1;
elseifyl<=0%确定边界
isOver=1;
elseifyr>n
isOver=1;
else
isOver=0;
end
ifisOver==1
threath=0;
return;
end
fori=centerX-w:
centerX+w
forj=centerY-w:
centerY+w%提取窗口内像素值
pix(1,pixNum)=image(i,j);
pixNum=pixNum+1;
end
end
maxNum=max(pix);
minNum=min(pix);
if((maxNum-local)>(local-minNum))
threath=0;
else
threath=255;
End
2.3基于hough变换的图像倾斜校正Matlab源代码
functionBW2=funRotate(BW)
%函数功能:
将输入的二值图像进行采用hough变换进行旋转
%输出:
旋转后的二值图像
BW2=BW;
BW=edge(BW,'canny');
[H,T,R]=hough(BW);
P=houghpeaks(H,10,'threshold',ceil(0.5*max(H(:
))));
lines=houghlines(BW,T,R,P,'FillGap',5,'MinLength',7);
max_len=0;
index=0;
fork=1:
length(lines)
len=norm(lines(k).point1-lines(k).point2);
if(len>max_len)
max_len=len;
index=k;
end
end
k=(lines(index).point2
(2)-lines(index).point1
(2))/(lines(index).point2
(1)-lines(index).point1
(1));
theta=atan(k)/pi*180;
iftheta>80||theta<-20
BW2=imrotate(BW2,theta,'bicubic');
end
3.1版面分割matlab源代码
function[B]=document_analysis(I,I0)
[B,B0]=Vertical_projection(I,I0);%图片粗分割
pictureID=1;
%图片精分割
fori=1:
length(B)
forj=1:
length(B{i})
P=[];
P0=[];
P0=B0{i}{j};
P=B{i}{j};
P1=edge(P,'canny');
figure;
imshow(P1);
[Bt,Bt0,Vlength]=VP(P,P0,0.9,0.01);%列投影取文字间隙[q1,q2]=k_cluster(Vlength,P);%k-聚类
P2=expand(P1,q1);%膨胀[P3,smalldomain,largedomain]=Connected_domain(P2,q2);%提取大小连通域
[mergeR,Merge,P4]=merge(smalldomain,P3);%小连通域合并[O,R,finalMergeR,P5]=furthermerge(mergeR,largedomain,P1);%大连通域合并
LineMergeR=Linemerge(finalMergeR);%线性合并,保证行信息不混乱
%保存图片
fork=1:
length(LineMergeR(:
1))
picture=[];
picture=P((LineMergeR(k,2)):
(LineMergeR(k,4)),(LineMergeR(k,1)):
(LineMergeR(k,3)));
[m,n]=size(picture);
Q=zeros(m+4,n+4);
Q(3:
m+2,3:
n+2)=picture;
picture=Q;
figure;
imshow(picture);
imwrite(picture,['C:
\Users\wzl1\Desktop\ÃûƬʶ±ðϵͳ\picture',num2str(pictureID),'.jpg']);
pictureID=pictureID+1;
end
end
end
4.1test.cpp
#include"strngs.h"
#include"baseapi.h"
#include
#include