Android应用开发进阶篇-场景文字识别

由于研究生毕业项目需要完成一个基于移动终端的场景文字识别系统,虽然离毕业尚早,但出于兴趣的缘故,近一段抽时间完成了这样一套系统。基本的架构如下:

客户端:Android应用实现拍摄场景图片,大致划出感兴趣文字区域,通过socket通信上传服务器端识别;

服务器端:Python server进行socket通信监听,连通后调用文字识别引擎(exe可执行程序),将识别结果返回;

下面是系统运行示例图:

1. 客户端

包含两个Activity,: MainActivity主界面如上图左1,选择拍摄后调用系统内部的拍照服务如上图左2;拍照完成进入KernelActivity如上图左3,大致划出感兴趣文字区域后上传服务器端,获取识别结果如上图左4。

客户端拍照和建立网络通信需要注意在AndroidManifestxml文件中声明权限

    <!-- 授权使用相机 -->
    <uses-permission android:name="android.permission.CAMERA" />
    <!-- 在SD卡中创建与删除文件的权限 -->
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
    <!-- 向SD卡中写入数据权限 -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <!-- 授权访问互联网 -->
    <uses-permission android:name="android.permission.INTERNET" /> 

客户端Android编程时连接服务器端利用socket进行通信,在编程过程中有几点需要注意的问题,不然很容易导致出错:

1.1 主线程中不能直接建立网络连接

为了防止线程阻塞,android 4.0以上的版本不允许直接在主线程建立网络连接(socket通信需要连接网络)。因此,在需要socket通信时,应新开线程用于网络连接,使用示例如下

new Thread(){//主线程不能直接连接网络,需新建子线程
	@Override
	public void run(){
		//TODO
	}
}.start();

1.2 客户端socket收发数据流不宜使用close()方法

客户端需要同时接受和发送数据,因此会有如下两个对象out和in

							//开始socket通信
							Socket socket = new Socket("210.77.27.123", 9058);	//此处IP根据自己的服务器端设定

							//写输出(上传)数据
							DataOutputStream out = new DataOutputStream(socket.getOutputStream());	

							//写输入(获得)数据
							BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream(), "gb2312")); //设置字符编码格式,以便正确读取中文

如果在out向服务器端发送完数据后,想着out已经不需要了,则可能会想使用 out.close() 关闭对象。如果这样,那么在使用in对象接收数据时便会抛出异常“socket closed”!原因是,in或out对象的close()方法使用后会造成socket的关闭。所以,如果需要关闭,可以考虑使用shutdownInput()和shutdownOutput()方法,或者不处理而待最后socket.close()即可。

1.3 子线程不能更新UI

获得服务器端识别结果时,需要使用这个内容更新客户端UI(左下角的TextView),如果在上面说到的进行socket通信的子线程中直接使用 text.setText()方法试图更新UI的话,结论是不可行的。所以,为了更新UI需要借助Handler对象,在其handleMessage()方法内更新UI。

子线程中将服务器端结果存入message并向预定义的handler对象发送消息

							String response = in.readLine();
							Message msg = handler.obtainMessage();//子线程中不能更新UI,需借助handler
							msg.obj = response;
							handler.sendMessage(msg);

紧接着handler会调用其 handleMessage()方法更新UI,handleMessage()定义如下

		handler = new Handler(){
			@Override
			public void handleMessage(Message msg){
				String message = (String)msg.obj;
				if(message != null)
				    text.setText(message);
				else
				    text.setText("抱歉,未能识别");
				super.handleMessage(msg);//这一句必须要有!不然无法更新UI
			}
		};

2.服务器端

服务器端主要部署python脚本进行socket监听,一旦建立连接则调用开发好的场景文字识别引擎(STREngine.exe),并将结果返回客户端。python server脚本内容如下

#####################################
#                                   #
#       STC Recognition Server      #
#                                   #
#####################################

import socket
import os

s = socket.socket()

host = socket.gethostname()
port = 9058
s.bind((host, port))

s.listen(5)
while True:
    c, addr = s.accept()
    print 'Got connection from' , addr

    #get uploaded params
    params = c.recv(19)
    lst = params.split(' ')
    if len(lst) < 4:
        c.close()
        continue
    print 'x=%d, y=%d, w=%d, h=%d' % (int(lst[0]),int(lst[1]),int(lst[2]),int(lst[3]))

    #get uploaded image size info
    size = int(c.recv(4))

    #save uploaded image
    f = open('.\\upload\\tmp.jpg', 'wb')
    for i in range(size):
        f.write(c.recv(1024))
    f.close()
    print 'Image received, size %dKB' % size

    #execute STREngine on server and send back the result
    result = os.popen('STREngine ./upload/tmp.jpg ' + params).read()
    print 'Recognition result:', result
    c.send(result + '\n')

    print 'Close connection with', addr, '\n'
    c.close()

文字识别引擎的内部代码不便分享,但会将可执行文件分享给感兴趣的朋友。

服务器端有一点非常重要的地方,不注意的话可能会给你带来无尽的烦恼,我就花了两个晚上才发现这个很小的问题,在此分享以免再浪费别人的时间:

在服务器端返回识别结果给客户端时,一定要在字符串后面加换行符‘\n’结尾!如果不加,则客户端 in.readline()方法会因找不到行末而一直阻塞,则无法利用返回结果更新客户端UI。这个问题非常恼人,因为如果你在服务端返回不加‘\n‘的话,在本地电脑上利用android虚拟机是没问题的,虚拟机上正常更新UI,但是一旦换到手机上就没反应了(不更新UI)。

总结:

其实,客户端手动划取感兴趣文字上传后,这个区域位置在ImageView和实际图像中是需要仔细换算的,这里就不细说了,有需要的朋友直接看代码吧。或者强烈建议自己分析推导一番,自己找出这个关系,会对加深对ImageView和Bitmap的理解有极大帮助。

此外,由于不是做产品,对效率的考虑并没有在意。现在的话是将手机拍照后的整幅图片上传,虽然进行了压缩,但一副图仍有几百KB大小,这对流量实在太过浪费。解决的话也简单,只要将划取的文字区域单独取出来上传即可(但四周需要一定程度的扩展),大小应该减小几十倍。

客户端和服务端源代码(包括识别引擎可执行程序)已分享至CSDN,有问题欢迎随时随时交流指正。

Android应用开发进阶篇-场景文字识别

时间: 2024-11-07 19:42:24

Android应用开发进阶篇-场景文字识别的相关文章

Android JNI开发提高篇

有关JNI的开发技术,我们继续围绕Android平台进行,JNI可以支持C或C++,从目前为止我们写过的JNI代码均为C实现的,即文件名为.C而C++的和这些有什么不同呢? Android平台上的JNI一般使用C还是C++编写呢? Android平台在中间层和大部分的类库的底层使用了C++的开发方式,后缀为.cpp,比如Android Framework.OpenCore.Webkit.SQLite等等.使用C++好处就是可以使用很多库但目前Android不支持STL,我们知道C表示字符串都是字

[转]抢先Mark!微信公众平台开发进阶篇资源集锦

FROM : http://www.csdn.net/article/2014-08-01/2820986 由CSDN和<程序员>杂志联合主办的 2014年微信开发者大会 将于8月23日在北京举行.作为一线微信开发商云集.专注在开发实践方面的顶级技术活动,演讲话题极为丰富,涵盖了微信开发不同维度的多个层内容 (首批议程发布),包括:企业服务号开发和高级应用.企业号开发.如何与业务系统对接.各种高级接口功能.智能客服与LBS.HTML5社交应用.微信支付.微信电商开发等多方面(查看 参加微信开发

Android应用开发提高篇(1)-----获取本地IP

链接地址:http://www.cnblogs.com/lknlfy/archive/2012/02/21/2361802.html 一.概述 习惯了Linux下的网络编程,在还没用智能机之前就一直想知道怎么得到手机的IP地址(玩智能机之前我是不搞手机应用的).好了,得知Android是基于Linux内核的,那么不就可以利用之前学的Linux下的网络编程方法来获取IP了吗?呵呵,其实这是比较底层的方法,在Android上,完全可以利用Java的API来实现,而且实现的代码非常简单.下面的实现只可

浅析点对点(End-to-End)的场景文字识别(图片文字)

一.背景 随着智能手机的广泛普及和移动互联网的迅速发展,通过手机等移动终端的摄像头获取.检索和分享资讯已经逐步成为一种生活方式.基于摄像头的 (Camera-based)的应用更加强调对拍摄场景的理解.通常,在文字和其他物体并存的场景,用户往往首先更关注场景中的文字信息,因而如何能够正 确识别场景中的文字,对用户拍摄意图会有更深入的理解.一般意义上,基于图像的文字识别包括基于扫描文字的光学字符识别(Optical Character Recognition, OCR) 和广泛用于网站注册验证的C

mysql 开发进阶篇系列 20 MySQL Server(innodb_lock_wait_timeout,innodb_support_xa,innodb _log_*)

1. innodb_lock_wait_timeout mysql 可以自动监测行锁导致的死锁并进行相应的处理,但是对于表锁导致的死锁不能自动监测,所以该参数主要用于,出现类似情况的时候等待指定的时间后回滚.系统默认值是50秒.用户可以根据业务自行设置.生产环境不推荐使用过大的 innodb_lock_wait_timeout 参数值. -- 查看事务超时时间 SHOW VARIABLES LIKE 'innodb_lock_wait_timeout'; 也可以对当前会话进行超时设置如: set

mysql 开发进阶篇系列 47 xtrabackup (完全备份恢复,恢复后重启失败总结)

一. 完全备份恢复说明 xtrabackup二进制文件有一个xtrabackup --copy-back选项,它将备份复制到服务器的datadir目录下.下面是通过 --target-dir 指定完全备份文件的目录,还原到datadir目录下. xtrabackup --copy-back --target-dir=/data/backups/ 可以使用xtrabackup --move-back选项恢复备份.这个选项类似于xtrabackup --copy-back,唯一的区别是它将文件移动到

mysql 开发进阶篇系列 55 权限与安全(安全事项 )

一. 操作系统层面安全 对于数据库来说,安全很重要,本章将从操作系统和数据库两个层面对mysql的安全问题进行了解. 1. 严格控制操作系统账号和权限 在数据库服务器上要严格控制操作系统的账号和权限,在安装mysql时就要重视安全问题. (1) 锁定mysql用户. (2) 其它任何用户都采取独立的账号登录,管理员通过mysql专有用户管理mysql服务,或者通过 root su到mysql用户下进行管理. (3) mysql用户目录下,除了数据文件目录,其它文件和目录属主都改为root. 我本

微信小程序开发——进阶篇

由于项目的原因,最近的工作一直围绕着微信小程序.现在也算告一段落,是时候整理一下这段时间的收获了.我维护的小程序有两个,分别是官方小程序和一个游戏为主的小程序.两个都是用了wepy进行开发,就是这个: 由于是进阶篇,所以一些有关于开发基础的我就直接跳过,直接讲我最近遇到的几个需求场景.写的急,可能顺序有一些乱,还请见谅! 用什么框架开发小程序? 现有的比较公认的有3个小程序开发框架: 原生.wepy.mpvue.3者个有利弊: 原生框架:微信的亲儿子,可直接在微信开发者工具中开发,方便调试,结构

Android应用开发基础篇(3)-----ListView

链接地址:http://www.cnblogs.com/lknlfy/archive/2012/02/16/2354625.html 一.概述 ListView是一个列表显示控件,它的应用非常广泛,在很多应用程序中都可以看到它的身影,比如来电通,网易新闻等等,特别是QQ.因此非常有必要熟练掌握它. 二.要求 能够利用ListView显示一些内容,如数据.文本,某一行被点击时有相应的提示:能够实现简单的ListView的动态插入和删除. 三.实现 新建工程MyListView,修改/res/lay