基于MATLAB的图片中文字的提取及识别
一.引言
随着计算机科学的飞速发展,以图像为主的多媒体信息迅速成为重要的信息传递媒介,在图像中,文字信息(如新闻标题等字幕) 包含了丰富的高层语义信息,提取出这些文字,对于图像高层语义的理解、索引和检索非常有帮助。图像文字提取又分为动态图像文字提取和静态图像文字提取两种,其中,静态图像文字提取是动态图像文字提取的基础,其应用范围更为广泛,对它的研究具有基础性,所以本文主要讨论静态图像的文字提取技术。静态图像中的文字可分成两大类: 一种是图像中场景本身包含的文字, 称为场景文字; 另一种是图像后期制作中加入的文字, 称为人工文字,如右图所示。场景文字由于其出现的位置、小、颜色和形态的随机性, 一般难于检测和提取;而人工文字则字体较规范、大小有一定的限度且易辨认,颜色为单色, 相对与前者更易被检测和提取,又因其对图像内容起到说明总结的作用,故适合用来做图像的索引和检索关键字。对图像中场景文字的研究难度大,目前这方面的研究成果与文献也不是很丰富,本文主要讨论图像中人工文字提取技术。
二.静态图像中文字的特点
静态图像中文字(本文特指人工文字,下同)具有以下主要特征:
(1)文字位于前端,且不会被遮挡;
(2)文字一般是单色的;
(3)文字大小在一幅图片中固定,并且宽度和高度大体相同,从满足人眼视觉感受的角度来说,图像中文字的尺寸既不会过大也不会过小;
(4)文字的分布比较集中;
(5)文字的排列一般为水平方向或垂直方向;
(6)多行文字之间,以及单行内各个字之间存在不同于文字区域的空隙。在静态图片文字的检测与提取过程中, 一般情况下都是依据上述特征进行处理的。
三.文字提取、识别的一般流程
静态图像文字提取一般分为以下步骤:文字区域检测与定位、文字分割与文字提取、文字后处理。其流程如图1所示。
(图1)
四.文字提取、识别的详细步骤
1. 在Matlab中调用i1=imread('字符.jpg'),可得到原始图像,如图2所示:
(图2)
2. 调用i2=rgb2gray(i1),则得到了灰度图像,如图3所示:
(图3)
调用a=size(i1);b=size(i2);可得到:a=3,b=2 即三维图像变成了二维灰度图像
3. 调用i3=(i2>=thresh);其中thresh为门限,在[0,255]之间
这里,i2_max=double(max(max(i2))); %获取亮度最大值
i2_min=double(min(min(i2))); %获取亮度最小值
thresh=round(i2_max-((i2_max-i2_min)/3));
得到二值图像,如图4所示:
(图4)
4. 把二值图像放大观察,可看到离散的黑点
对其采用腐蚀膨胀处理,得到处理后的图像,如图5所示
(图5)
可见,腐蚀膨胀处理后的图像质量有了很大的改观。
横向、纵向分别的腐蚀膨胀运算比横向、纵向同时的腐蚀膨胀运算好上很多,图6可看出差别:
(图6)
5. 对腐蚀膨胀后的图像进行Y方向上的区域选定,限定区域后的图像如图7所示:
扫描方法:中间往两边扫
(图7)
纵向扫描后的图像与原图像的对照,如图8所示:
(图8)
6.对腐蚀膨胀后的图像进行X方向上的区域选定,限定区域后的图像如图9所示:
扫描方法:两边往中间扫
(图9)
纵向扫描后的图像与原图像的对照,如图10所示:
(图10)
7. 调用i8=(iiXY~=1),使背景为黑色(0),字符为白色(1),便于后期处理。
背景交换后的图像如图11所示:
(图11)
8. 调用自定义函数(字符获取函数)i9=getchar(i8),得到图像如图12所示:
(图9)
9.调用自定义的字符获取函数对图像进行字符切割,并把切割的字符装入一维阵列,切割 过程如图12所示:
(图12)
10.调用以下代码,可将阵列word中的字符显示出来,如图13所示:
for j=1:cnum %cnum为统计的字符个数
subplot(5,8,j),imshow(word{j}),title(int2str(j)); %显示字符
end
(图13)
可以看到,字符宽度不一致
11.调用以下代码,将字符规格化,便于识别:
for j=1:cnum
word{j}=imresize(word{j},[40 40]); %字符规格化成40×40的
end
得到规格化之后的字符如图14所示:
(图14)
12.调用以下代码创建字符集:
code=char('由于作者水平有限书中难免存在缺点和疏漏之处恳请读批评指正,。');
将创建的字符集保存在一个文件夹里面,以供匹配时候调用,如图15所示:
(图15)
13.字符匹配采用模板匹配算法:将现有字符逐个与模板字符相减,认为相减误差最小的现 有字符与该模板字符匹配。
假设:字符,模板字符,模板字符
也就是说,字符A与模板字符更相似,我们可以认为字符集中的字符就是字符A。
经模板匹配,可得字符信息如下:
由于读者书评有限书中难免存在缺点和纰漏之处,恳请读者批评指正。
效果如图16所示:
(图16)
14.调用以下代码,将字符放入newtxt.txt文本:
new=['newtxt','.txt'];
c=fopen(new,'a+');
fprintf(c,'%s\n',Code(1:cnum));
fclose(c);
newtxt.txt文本内容如图17所示:
(图17)
五、代码附录
主程序源代码:
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%% 数字图象处理大作业 %%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%————————图片中文字的提取及识别————————%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
tic
I=imread('字符.jpg'); %打开图片
%figure(1);imshow(I);title('原始图像','color','b');
I=rgb2gray(I); %RGB图片转化成灰度图像
%figure(2);imshow(I);title('灰度图像','color','b');
i_max=double(max(max(I))); %获取亮度最大值
i_min=double(min(min(I))); %获取亮度最小值
thresh=round(i_max-((i_max-i_min)/3)); %计算灰度图像转化成二值图像的门限thresh
I=(I>=thresh); %I为二值图像
%figure(3);imshow(I);title('二值图像','color','b');
seY=[1;1;1]; %构造结构元素
I=imdilate(I,seY); %腐蚀图像
I=imerode(I,seY); %膨胀图像
seX=[1 1 1];
I=imdilate(I,seX);
I=imerode(I,seX);
%figure(4);imshow(I);title('腐蚀膨胀后的图像','color','b');
ii=double(I);
[m,n]=size(ii); %获取图像大小信息
%确定文字区域
%纵向扫描
countY=zeros(m,1);
[maxY indexY]=max(countY);
tempY1=indexY;
while (countY(tempY1,1)>3) && (tempY1>1)
tempY1=tempY1-1;
end
tempY2=indexY;
while (countY(tempY2,1)>3) && (tempY2<m)
tempY2=tempY2+1;
end
tempY1=tempY1-1;
tempY2=tempY2+1;
iiY=I(tempY1:tempY2,:); %确定了Y方向上的文字区域
%figure(5);imshow(iiY);title('Y方向区域大致确定后的图像','color','b');
%横向扫描
countX=zeros(1,n);
end
tempX1=1;
while (countX(1,tempX1)<3) && (tempX1<n)
tempX1=tempX1+1;
end
tempX2=n;
while (countX(1,tempX2)<3) && (tempX2>1)
tempX2=tempX2-1;
end
tempX1=tempX1-1;
tempX2=tempX2+1;
iiXY=iiY(:,tempX1:tempX2); %确定了整体的文字区域
%figure(6);imshow(iiXY);title('X、Y方向区域都大致确定后的图像','color','b');
ii=(iiXY~=1);%黑色背景,白色字体
%figure(7);imshow(ii);title('背景和文字交换颜色的图像','color','b');
ii=bwareaopen(ii,200); %删除面积小于200的杂质图像
%figure(8);imshow(ii);title('删除杂质干扰的图像','color','b');
myI=charslice(ii); %限定文字区域
%figure(9);imshow(ii);title('限定文字区域的图像','color','b');
figure(10)
while size(myI,2)>10 %当myI的长度小等于10,可确定没有字符了
[word{k},myI]=getword(myI); %获取字符
k=k+1;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if k==2
subplot(5,1,1);imshow(myI);title('第一次切割后的图像','color','b');
end
if k==3
subplot(5,1,2);imshow(myI);title('第二次切割后的图像','color','b');
end
if k==5
subplot(5,1,3);imshow(myI);title('第四次切割后的图像','color','b');
end
if k==16
subplot(5,1,4);imshow(myI);title('第十五次切割后的图像','color','b');
end
end
subplot(5,1,5);imshow(myI);title('最后一次切割后的图像','color','b');
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cnum=k-1; %实际字符总个数
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
figure(11);
for j=1:cnum
subplot(5,8,j),imshow(word{j}),title(int2str(j)); %显示字符
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
for j=1:cnum
word{j}=imresize(word{j},[40 40]); %字符规格化成40×40的
end
figure(12);
for j=1:cnum
subplot(5,8,j),imshow(word{j}),title(int2str(j)); %显示字符
end
defx=40;defy=40;
code=char('由于作者水平有限书中难免存在缺点和疏漏之处恳请读批评指正,。');%创建字符集
codenum=size(code,2); %获取字符集中字符个数
for i=1:cnum
ch=int2str(i); %数字转化为字符
tempbw=imread([ch '.jpg']); %打开预匹配字符
for k=1:codenum
fname=strcat('C:\Users\Administrator\Desktop\数字图像处理\字符匹配库\',code(k),'.jpg'); %字符匹配库中的字符
sample=imread(fname);
subsam=abs(tempbw-sample); %作比较
count=sum(sum(subsam)); %匹配误差统计
err(k)=count;
end
erro=err(1:codenum);
minerror=min(erro); %找出误差最小的模板字符
findc=find(erro==minerror); %获取模板字符序号
Code(i)=code(findc); %将字符装入Code
end
figure(13);
imshow(ii);
tt=title(['文字信息: ', Code(1:cnum)],'Color','b'); %显示字符信息
set(tt,'fontsize',24); %设置字体
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%将图片文字写入newtxt文本
new=['newtxt','.txt'];
c=fopen(new,'a+');
fprintf(c,'%s\n',Code(1:cnum));
fclose(c);
t=toc
charslice(字符分割)函数源代码:
%字符分割
function y=charslice(ii)
[m,n]=size(ii);
top=1;bottom=m;left=1;right=n;
while sum(ii(top,:))==0 && top<m
top=top+1;
end
while sum(ii(bottom,:))==0 && bottom>=1
bottom=bottom-1;
end
while sum(ii(:,left))==0 && left<n
left=left+1;
end
while sum(ii(:,right))==0 && right>=1
right=right-1;
end
ydiff=bottom-top;
xdiff=right-left;
y=imcrop(ii,[left top xdiff ydiff]);
getword(字符获取)函数源代码:
%字符获取
function [word,result]=getword(ii)
word=[];flag=0;y1=8;y2=0.5;
while flag==0
[m,n]=size(ii);
wide=0;
while sum(ii(:,wide+1))~=0 && wide<=n-2
wide=wide+1;
end
temp=charslice(imcrop(ii,[1 1 wide m]));
[m1,n1]=size(temp);
if wide<y1 && n1/m1>y2
ii(:,1:wide)=0;
if sum(sum(ii))~=0
ii=charslice(ii); % 切割出最小范围
else word=[];flag=1;
end
else
word=charslice(imcrop(ii,[1 1 wide m]));
ii(:,1:wide)=0;
if sum(sum(ii))~=0;
ii=charslice(ii);
flag=1;
else ii=[];
end
end
end
result=ii;