Android中的文字识别(论文精简版)
2015-08-15 10:51
381 查看
这是年少的我的第一篇博客啊~~~
下图文字识别的工作流程。主要用到OpenCV4JAVA的图像处理功能与Tesseract的文字识别库。
![](https://img-blog.csdn.net/20150815105745506?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
通过图像处理、文字识别两个步骤后,接下来我们要进行的是APP的UI界面刷新,这个过程通过定义一个handler来handleMessage实现,因为android的UI更新只能在主线程里操作,并且文字处理由于时间过长需要在另外的线程里处理,所以只能通过android的这个通知刷新机制来实现。
下面是每一步的细节。
任何颜色都由三种原色组成,红色、蓝色、绿色。表示为 RGB(R,G,B)。每个颜色通道有256阶,当三个颜色通道的值均相等时,这就是一个灰阶,从此可以得出灰度可以分为256阶。由于每个点的色值可以是256的3次方约1677万种可能,所以一张三通道图片的数据量是十分浩大的,这对与程序处理极为不利,需要耗费极长的时间。但是对原图灰度化之后,一个点的色值只有256种可能,瞬间缩小工作量,而且过滤的色值对于我们课题也是并无大用的,因为文字识别一般都建立在白纸黑字的基础之上。采用灰度图,可以使得我们文字识别的算法在时间上变得可能。图2.1展示的是灰度图与原图的对比。左图为灰度图,右图为原图。从图中我们可以看出来,灰度化效果比较理想。
本课题灰度化使用的方法是OpenCV里的cvtColor(Matsrc, Mat dst, int code);
src:输入待处理的图片;
dst:输出处理后的图片;
code:颜色区域,表示从什么颜色转换成目标颜色,本课题此处用的是Imgproc.COLOR_RGB2GRAY;
![](https://img-blog.csdn.net/20150815110644836?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
总体来讲,我们一般选用局部自适应阀值二值化,也是本课题的选择。二值化的时候我们使用OpenCV的:
adaptiveThreshold(Mat src, Mat
dst, double
maxValue, int
adaptiveMethod, int
thresholdType, int
blockSize, double
C);
maxValue:二值化时允许黑色像素的最大色值,一般我们选255;
adaptiveMethod:局部自适应方法,本课题选用的是Imgproc的ADAPTIVE_THRESH_MEAN_C;
thresholdType:二值化类型,也是一个选项,我们使用的时候一般选用Imgproc.THRESH_BINARY_INV;
blockSize:一般为3,5,7等奇数,因为算法决定这样的运算速率较快。这个参数是指以附近n*n个像素作为参考,计算中心像素的二值化值。
下面展示局部自定义阀值与固定阀值二值化的区别。如下图,左图采用的是局部自定义阀值二值化,而右图采用的是固定阀值二值化。从图中我们可以明显看出,采用局部阀值二值化处理后的图像的内容比较多且杂,但是基本没有丢失重要内容,文字与背景的对比明显。但是从右图可以看出,右侧文字已经与背景融为一体,难以分辨了。
![](https://img-blog.csdn.net/20150815111044978?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
在本课题中的腐蚀膨胀我们使用OpenCV中的
erode(Mat src,Mat
dst, Mat kernel)和
dilate(Mat src, Mat
dst, Mat kernel);
kernel:是一个腐蚀膨胀计算的核心,他是这么定义的。
Mat kernel = Imgproc.getStructuringElement(
Imgproc.MORPH_RECT,new Size(2, 2));
![](https://img-blog.csdn.net/20150815111313932?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
如图2.4,左图是倾斜的原图,右图是经过hough变换的图,找到字里行间有直线特征的像素连成一条直线,保存好所有直线的起点与终点,计算其斜率获得倾斜角,计算所有直线的倾斜角的均值,然后把原图按均值旋转一个角度。需要注意的是,这种方法在倾斜角小于90度的时候都有较好的纠正作用。从右图中我们可以看到其中有几条明显的细线。那些线是用来参考用的,真实识别文字的时候会把这些细线去掉。
在本课题中,我们使用OpenCV的houghLines方法对图片检测直线。
HoughLinesP(Mat image, Mat lines, double rho, double theta, int threshold, double minLineLength, doublemaxLineGap)
rho:累加的以像素为单位的距离分辨率,我们使用1;
theta:以弧度为单位的累加的角度分辨率我们使用π/180;
threshold:某个像素的色值大于此,该方法才会在直线检测的时候把该像素纳 入考虑;
minLineLength:最小的直线长度,小于此的不予考虑;
maxLineGap:连成直线的两点的之间的最大距离,大于此的不予考虑。
houghLines方法处理图片后,会记录下一条直线的起点与终点放入lines变量内此时我们可以计算两点的斜率,从而求的文字倾斜的角度。
Double sum = 0.0;
for (Double d : angle) {
sum += d;
}
float ave = Float.valueOf(sum /angle.size()
+ "");
![](https://img-blog.csdn.net/20150815111335256?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
![](https://img-blog.csdn.net/20150815111605018?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
![](https://img-blog.csdn.net/20150815111618588?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
以上的文字图片都是接近端正、水平的,接下来我们看下软件对倾斜文字的识别效果。如图4.6所示。图4.6中,左侧是软件正在处理原图的,识别文字时候的截图,中间图片是软件处理后的图片,从中我们可以看到,对于传入的倾斜的图片,本课题已经按照逻辑旋转了一个角度,使得文字行水平。右图中白框是我们显示的识别后的结果。在这结果中我们可以看出,本课题对倾斜文字有较好的识别作用,除了个别文字不完整识别错误与个别文字由于处理不清晰导致识别失败,其他文字都正确识别,识别率可观。
![](https://img-blog.csdn.net/20150815111740668?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
下面我们来看一下应用对从相册获得的整齐文字截图的识别结果,如图4.7所示。识别结果可以看出,相对于前面的识别结果,这个截图的识别率显然更高。
![](https://img-blog.csdn.net/20150815111827650?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
整个过程大概方向上就这几个方面,这几个截图都是本人实测的。在文字识别方面我也只是刚刚接触,写这篇博客也是让尚未接触这方面的朋友稍微有点帮助。
下图文字识别的工作流程。主要用到OpenCV4JAVA的图像处理功能与Tesseract的文字识别库。
通过图像处理、文字识别两个步骤后,接下来我们要进行的是APP的UI界面刷新,这个过程通过定义一个handler来handleMessage实现,因为android的UI更新只能在主线程里操作,并且文字处理由于时间过长需要在另外的线程里处理,所以只能通过android的这个通知刷新机制来实现。
下面是每一步的细节。
灰度图
灰度图(Gray Scale Image)又称灰阶图,它是指把白色与灰色按对数关系分为若干等级,称作灰阶。灰度分为256阶,用灰度表示的图像称为灰度图。任何颜色都由三种原色组成,红色、蓝色、绿色。表示为 RGB(R,G,B)。每个颜色通道有256阶,当三个颜色通道的值均相等时,这就是一个灰阶,从此可以得出灰度可以分为256阶。由于每个点的色值可以是256的3次方约1677万种可能,所以一张三通道图片的数据量是十分浩大的,这对与程序处理极为不利,需要耗费极长的时间。但是对原图灰度化之后,一个点的色值只有256种可能,瞬间缩小工作量,而且过滤的色值对于我们课题也是并无大用的,因为文字识别一般都建立在白纸黑字的基础之上。采用灰度图,可以使得我们文字识别的算法在时间上变得可能。图2.1展示的是灰度图与原图的对比。左图为灰度图,右图为原图。从图中我们可以看出来,灰度化效果比较理想。
本课题灰度化使用的方法是OpenCV里的cvtColor(Matsrc, Mat dst, int code);
src:输入待处理的图片;
dst:输出处理后的图片;
code:颜色区域,表示从什么颜色转换成目标颜色,本课题此处用的是Imgproc.COLOR_RGB2GRAY;
二值图
二值图是作为图像处理最常用的图。二值图像是指每个像素不是黑就是白,其灰度值没有中间过渡的图像。二值图像一般用来描述文字或者图形,其优点是占用空间少,缺点是,当表示人物,风景的图像时,二值图像只能描述其轮廓,不能描述细节。这时候要用更高的灰度级。二值图像是每个像素只有两个可能值的数字图像。人们经常用黑白、B&W、单色图像表示二值图像,但是也可以用来表示每个像素只有一个采样值的任何图像,例如灰度图像等。二值图的图像中所有的像素点只能从0和1中取值。对于一张灰度图,有256种色值可能,如果我们选取一个阀值,例如100。遍历这个灰度图的每个像素,若像素色值小于100,则置其为0,若大于等于100,则置其为1,处理后的图像就是二值图。这种灰度图转换为二值图的方法叫固定阀值二值化。除了固定阀值二值化,这里还有一个方法叫局部自适应阀值二值化。它是选取目标像素周边的值来确定该像素的值。局部自适应阀值二值化的优点是基本能够全面的显示原图的内容,而固定阀值二值化容易造成某部分内容整片缺失。总体来讲,我们一般选用局部自适应阀值二值化,也是本课题的选择。二值化的时候我们使用OpenCV的:
adaptiveThreshold(Mat src, Mat
dst, double
maxValue, int
adaptiveMethod, int
thresholdType, int
blockSize, double
C);
maxValue:二值化时允许黑色像素的最大色值,一般我们选255;
adaptiveMethod:局部自适应方法,本课题选用的是Imgproc的ADAPTIVE_THRESH_MEAN_C;
thresholdType:二值化类型,也是一个选项,我们使用的时候一般选用Imgproc.THRESH_BINARY_INV;
blockSize:一般为3,5,7等奇数,因为算法决定这样的运算速率较快。这个参数是指以附近n*n个像素作为参考,计算中心像素的二值化值。
下面展示局部自定义阀值与固定阀值二值化的区别。如下图,左图采用的是局部自定义阀值二值化,而右图采用的是固定阀值二值化。从图中我们可以明显看出,采用局部阀值二值化处理后的图像的内容比较多且杂,但是基本没有丢失重要内容,文字与背景的对比明显。但是从右图可以看出,右侧文字已经与背景融为一体,难以分辨了。
图像去噪声
由于原图有种种不可预测的因素造成图像中的噪声,为了保证应用对于较小字体的识别率,在此我们没有采用高斯或者均值滤波,而是采用对二值图腐蚀与膨胀操作来去除噪声。图像的腐蚀与膨胀默认都是对于二值图中的白色区域部分来说的,按照逻辑,我们应该先进行腐蚀操作,将图中的无用处的白点腐蚀掉,然后对操作后的图像进行膨胀操作还原字体。需要注意的是,在这里我们不能对二值图进行过多的连续腐蚀操作,这样会造成其中的文字部分被完全腐蚀掉。下面两张图展示的是对二值图进行腐蚀与膨胀操作后的结果。如图2.3所示,左图为二值图的腐蚀结果,右图为腐蚀图的膨胀结果。从图中的对比结果中可以看出,我们已经去掉了极大多数的噪声点。在本课题中的腐蚀膨胀我们使用OpenCV中的
erode(Mat src,Mat
dst, Mat kernel)和
dilate(Mat src, Mat
dst, Mat kernel);
kernel:是一个腐蚀膨胀计算的核心,他是这么定义的。
Mat kernel = Imgproc.getStructuringElement(
Imgproc.MORPH_RECT,new Size(2, 2));
Hough变换倾斜校正
当我们获得了上面一系列处理后的图之后,还需要考虑一个问题,那就是文字的倾斜问题。在实际应用中,我们无法保证用户会很端正的拿着手机拍照,他们可能会略有倾斜的拍。但是为了文字识别的效率与正确率,对于倾斜的文字,我们是必须要校正的。对图像中文字的校正,可以采用OpenCV中的hough变换来处理。Hough变换是一种使用表决原理的参数估计技术。其原理是利用图像空间和Hough参数空间的点-线对偶性,把图像空间中的检测问题转换到参数空间。通过在参数空间里进行简单的累加统计,然后在Hough参数空间寻找累加器峰值的方法检测直线。Hough变换的实质是将图像空间内具有一定关系的像元进行聚类,寻找能把这些像元用某一解析形式联系起来的参数空间累积对应点。在参数空间不超过二维的情况下,这种变换有着理想的效果。如图2.4,左图是倾斜的原图,右图是经过hough变换的图,找到字里行间有直线特征的像素连成一条直线,保存好所有直线的起点与终点,计算其斜率获得倾斜角,计算所有直线的倾斜角的均值,然后把原图按均值旋转一个角度。需要注意的是,这种方法在倾斜角小于90度的时候都有较好的纠正作用。从右图中我们可以看到其中有几条明显的细线。那些线是用来参考用的,真实识别文字的时候会把这些细线去掉。
在本课题中,我们使用OpenCV的houghLines方法对图片检测直线。
HoughLinesP(Mat image, Mat lines, double rho, double theta, int threshold, double minLineLength, doublemaxLineGap)
rho:累加的以像素为单位的距离分辨率,我们使用1;
theta:以弧度为单位的累加的角度分辨率我们使用π/180;
threshold:某个像素的色值大于此,该方法才会在直线检测的时候把该像素纳 入考虑;
minLineLength:最小的直线长度,小于此的不予考虑;
maxLineGap:连成直线的两点的之间的最大距离,大于此的不予考虑。
houghLines方法处理图片后,会记录下一条直线的起点与终点放入lines变量内此时我们可以计算两点的斜率,从而求的文字倾斜的角度。
Double sum = 0.0;
for (Double d : angle) {
sum += d;
}
float ave = Float.valueOf(sum /angle.size()
+ "");
tesseract简述
Tesseract:开源的OCR识别引擎,初期Tesseract引擎由HP实验室研发,后来贡献给了开源软件业,后经由Google进行改进,消除bug,优化,重新发布,在版本3.0的时候已支持汉字识别。本课题选用tess-two开源库,tess-two是托管在GIT上的tesseract-adroid-tools的一个分支,并添加了许多额外功能。tesseract android 工具包含了一整套android api和tesseract OCR和Leptonica图像处理库相关的build文件。在本课题中,我们把如图8没有加细线的图片数据传给tess-two,系统会用库里的字典与图片中的文字比较,来获得文字。本课题中,我们获得的文字不用写入某个文件,直接在程序中显示出来。识别测试
如图4.4测试结果。这是传入识别的图片,图4.5是识别结果。从图4.5中我们可以看出软件的识别率是比较高的。有个别文字由于种种原因未正确识别,对于标点符号,识别情况不是很乐观。图中共有128个字,有两字汉字未正确识别,此图识别率在98%以上。以上的文字图片都是接近端正、水平的,接下来我们看下软件对倾斜文字的识别效果。如图4.6所示。图4.6中,左侧是软件正在处理原图的,识别文字时候的截图,中间图片是软件处理后的图片,从中我们可以看到,对于传入的倾斜的图片,本课题已经按照逻辑旋转了一个角度,使得文字行水平。右图中白框是我们显示的识别后的结果。在这结果中我们可以看出,本课题对倾斜文字有较好的识别作用,除了个别文字不完整识别错误与个别文字由于处理不清晰导致识别失败,其他文字都正确识别,识别率可观。
下面我们来看一下应用对从相册获得的整齐文字截图的识别结果,如图4.7所示。识别结果可以看出,相对于前面的识别结果,这个截图的识别率显然更高。
整个过程大概方向上就这几个方面,这几个截图都是本人实测的。在文字识别方面我也只是刚刚接触,写这篇博客也是让尚未接触这方面的朋友稍微有点帮助。
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories