最近做了一款Android应用需要输入大量的数据,为了提高体验我想了很多种输入数据的方式,最终采用了两种:二维码扫描和图片识别。前者顾名思义有个短板,就是需要生成二维码,下面就介绍下图片文字识别实现。

本应用是基于是OCR引擎,故需要第三方的jar包 tess-two.tesseract3.01-leptonica1.68-LibJPEG6b.jar 下载链接:点击打开链接

另外tessdata是语言包(我只下载了中文和英语包)下载链接:点击打开链接,需要放到手机SD卡根目录,我的应用中直接打包进apk中,免得需要拷贝的麻烦,但是造成的结果就是apk体积变得非常大,各位根据各自的情况做取舍,后面我会贴出打包进apk的方法。

首先介绍下布局文件,本应用为一个简单地实现,界面上就没有多做处理,主界面如下图:

如上图,可以选择是否二值化处理图片再识别文字,然后选泽需要识别的文字种类,紧接着可以选择拍摄或者相片选取,识别后文字显示在编辑框内,可修改识别错误后,点击复制到安卓粘贴板,具体的代码如下,就不多说了:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:paddingBottom="@dimen/activity_vertical_margin"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"tools:context=".TesMainActivity"android:background="@drawable/beijing6" ><LinearLayoutandroid:id="@+id/bottombar1"android:layout_width="fill_parent"android:layout_height="wrap_content"android:layout_alignParentBottom="true" ><Buttonandroid:id="@+id/btn_capy"android:layout_weight="4" android:layout_width="fill_parent"android:layout_height="fill_parent"android:text="复制" /><Buttonandroid:id="@+id/btn_select"android:layout_weight="4" android:layout_width="fill_parent"android:layout_height="fill_parent"android:text="相册选取" /><Buttonandroid:id="@+id/btn_camera"android:layout_weight="4" android:layout_width="fill_parent"android:layout_height="fill_parent"android:text="拍照" /></LinearLayout> <RelativeLayoutandroid:id="@+id/bottombar"android:layout_width="fill_parent"android:layout_height="wrap_content"android:layout_above="@id/bottombar1"><RadioGroupandroid:id="@+id/radiogroup"android:layout_width="wrap_content"android:layout_height="50dp"android:layout_alignParentLeft="true"android:orientation="horizontal" ><RadioButtonandroid:id="@+id/rb_en"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_vertical"android:checked="true"android:text="英" /><RadioButtonandroid:id="@+id/rb_ch"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_vertical"android:text="中" /></RadioGroup></RelativeLayout><ScrollViewandroid:layout_width="fill_parent"android:layout_height="wrap_content"android:layout_above="@id/bottombar"android:layout_alignParentTop="true" ><LinearLayoutandroid:layout_width="fill_parent"android:layout_height="wrap_content"android:orientation="vertical" ><CheckBoxandroid:id="@+id/ch_pretreat"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="二值化处理" /><TextViewandroid:id="@+id/tv_result1"android:layout_width="fill_parent"android:layout_height="wrap_content"android:text="result" /><LinearLayout    android:focusable="true"    android:focusableInTouchMode="true"    android:layout_width="0px"    android:layout_height="0px"/><EditTextandroid:id="@+id/tv_result"android:layout_width="fill_parent"android:layout_height="wrap_content"/><TextViewandroid:layout_width="fill_parent"android:layout_height="wrap_content"android:text="选取的图片:" /><ImageViewandroid:id="@+id/iv_selected"android:layout_width="wrap_content"android:layout_height="wrap_content"android:adjustViewBounds="true"android:maxHeight="300dp" /><TextViewandroid:layout_width="fill_parent"android:layout_height="wrap_content"android:text="预处理后的图片:" /><ImageViewandroid:id="@+id/iv_treated"android:layout_width="wrap_content"android:layout_height="wrap_content"android:adjustViewBounds="true"android:maxHeight="300dp" /></LinearLayout></ScrollView></RelativeLayout>

接着说明下Activity,在界面初始化是会对语言包文件夹进行判断,如果没有该文件进行复制,另外还会初始化各种控价,代码如下:

@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_tesmain);// 若文件夹不存在 首先创建文件夹File path = new File(IMG_PATH);if (!path.exists()) {path.mkdirs();}tvResult = (EditText) findViewById(R.id.tv_result);tvResult1 = (TextView) findViewById(R.id.tv_result1);ivSelected = (ImageView) findViewById(R.id.iv_selected);ivTreated = (ImageView) findViewById(R.id.iv_treated);btnCamera = (Button) findViewById(R.id.btn_camera);btnSelect = (Button) findViewById(R.id.btn_select);btnCapy = (Button) findViewById(R.id.btn_capy);chPreTreat = (CheckBox) findViewById(R.id.ch_pretreat);radioGroup = (RadioGroup) findViewById(R.id.radiogroup);btnCamera.setOnClickListener(new cameraButtonListener());btnSelect.setOnClickListener(new selectButtonListener());btnCapy.setOnClickListener(new capyButtonListener());if(!isDirExist("tessdata")){Toast.makeText(getApplicationContext(), "SD卡缺少语言包,复制中。。。",Toast.LENGTH_LONG).show();new SaveFile_Thread().start();}// 用于设置解析语言radioGroup.setOnCheckedChangeListener(new OnCheckedChangeListener() {@Overridepublic void onCheckedChanged(RadioGroup group, int checkedId) {switch (checkedId) {case R.id.rb_en:LANGUAGE = "eng";break;case R.id.rb_ch:LANGUAGE = "chi_sim";break;}}});}

其中文件复制线程的代码如下:

 public boolean SaveFileToSDCard(){SDUtils sdutils_Chinese = new SDUtils("tessdata","chi_sim.traineddata",this,R.raw.chi_sim);SDUtils sdutils_English = new SDUtils("tessdata","eng.traineddata",this,R.raw.eng);try {sdutils_Chinese.getSQLiteDatabase();sdutils_English.getSQLiteDatabase();} catch (IOException e) {return false;}return true;}public class SaveFile_Thread extends Thread {public SaveFile_Thread(){}public void run(){synchronized (this) {boolean iret;do {iret = SaveFileToSDCard();} while (false);if(iret){ShowMsg(1);}elseShowMsg(2);}}}public void ShowMsg(int what) {mLoadKeyHandler.sendEmptyMessage(what);}public Handler mLoadKeyHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {if(msg.what==1){Toast.makeText(getApplicationContext(), "复制成功",Toast.LENGTH_LONG).show();}else if(msg.what==2)Toast.makeText(getApplicationContext(), "复制失败",Toast.LENGTH_LONG).show();}};

对SD卡进行文件操作我编辑了一个SDUtils 类,具体如下:

package com.mikewong.tool.tesseract;import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.os.Environment;
import android.util.Log;/**
* 工具类 , 用于将RAW 目录下的文件写入到数据库中
*
* @author Administrator
*
*/
public class SDUtils {private String file; // 设置文件存放路径private String fileName; // 存放文件名称private Context context; // 获取到Context 上下文private int rawid; // 资源文件ID ,需要COPY 的文件private String DATABASE_PATH = "";private String DATABASE_NAME = "";public String getFile() {return file;}public void setFile(String file) {this.file = file;this.DATABASE_PATH = Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + file;}public String getFileName() {return fileName;}public void setFileName(String fileName) {this.fileName = fileName;this.DATABASE_NAME = fileName;}public int getRawid() {return rawid;}public void setRawid(int rawid) {this.rawid = rawid;}public SDUtils() {}/*** * @param file*            文件夹例如: aa/bb* @param fileName*            文件名* @param context*            上下文* @param rawid*            资源ID*/public SDUtils(String file, String fileName, Context context, int rawid) {super();this.file = file;this.fileName = fileName;this.context = context;this.rawid = rawid;this.DATABASE_PATH = Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + file;this.DATABASE_NAME = fileName;}/*** 将文件复制到SD卡* * @return* @throws IOException*/public boolean getSQLiteDatabase() throws IOException {// 首先判断该目录下的文件夹是否存在File dir = new File(DATABASE_PATH);String filename1 = DATABASE_PATH + "/" + DATABASE_NAME;if (!dir.exists()) {// 文件夹不存在 , 则创建文件夹dir.mkdirs();}// 判断目标文件是否存在File file1 = new File(dir, DATABASE_NAME);if (!file1.exists()) {Log.i("msg", "没有文件,开始创建");file1.createNewFile(); // 创建文件}Log.i("msg", "准备开始进行文件的复制");// 开始进行文件的复制InputStream input = context.getResources().openRawResource(rawid); // 获取资源文件raw// 标号try {FileOutputStream out = new FileOutputStream(file1); // 文件输出流、用于将文件写到SD卡中// -- 从内存出去byte[] buffer = new byte[1024];int len = 0;while ((len = (input.read(buffer))) != -1) { // 读取文件,-- 进到内存out.write(buffer, 0, len); // 写入数据 ,-- 从内存出}input.close();out.close(); // 关闭流return true;} catch (Exception e) {Log.i("msg", "复制异常");return false;}}}

三个按钮所对应的操作代码:

 // 拍照识别class cameraButtonListener implements OnClickListener {@Overridepublic void onClick(View arg0) {Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);intent.putExtra(MediaStore.EXTRA_OUTPUT,Uri.fromFile(new File(IMG_PATH, "temp.jpg")));startActivityForResult(intent, PHOTO_CAPTURE);}};// 复制数据到剪切板class capyButtonListener implements OnClickListener {@Overridepublic void onClick(View arg0) {ClipboardManager cm = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);// 将文本内容放到系统剪贴板里。if(tvResult.length() == 0){Toast.makeText(getApplicationContext(), "无数据", Toast.LENGTH_SHORT).show();return;}cm.setText(tvResult.getText());Toast.makeText(getApplicationContext(), "复制成功", Toast.LENGTH_SHORT).show();}};// 从相册选取照片并裁剪class selectButtonListener implements OnClickListener {@Overridepublic void onClick(View v) {// 激活系统图库,选择一张图片Intent intent = new Intent(Intent.ACTION_PICK);intent.setType("image/*");// 开启一个带有返回值的Activity,请求码为PHOTO_REQUEST_GALLERYboolean dele= delete(new File(IMG_PATH));startActivityForResult(intent, PHOTO_REQUEST_GALLERY);}}

处理的回调函数

@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {if (resultCode == Activity.RESULT_CANCELED)return;if (requestCode == PHOTO_CAPTURE) {tvResult1.setText("abc");startPhotoCrop(Uri.fromFile(new File(IMG_PATH, "temp.jpg")));}if (requestCode == PHOTO_REQUEST_GALLERY) {startPhotoCrop(data.getData());}// 处理结果if (requestCode == PHOTO_RESULT) {bitmapSelected = decodeUriAsBitmap(Uri.fromFile(new File(IMG_PATH,"temp_cropped.jpg")));if (chPreTreat.isChecked())tvResult1.setText("预处理中......");elsetvResult1.setText("识别中......");// 显示选择的图片showPicture(ivSelected, bitmapSelected);// 新线程来处理识别new Thread(new Runnable() {@Overridepublic void run() {if (chPreTreat.isChecked()) {bitmapTreated = ImgPretreatment.doPretreatment(bitmapSelected);Message msg = new Message();msg.what = SHOWTREATEDIMG;myHandler.sendMessage(msg);textResult = doOcr(bitmapTreated, LANGUAGE);} else {bitmapTreated = ImgPretreatment.converyToGrayImg(bitmapSelected);Message msg = new Message();msg.what = SHOWTREATEDIMG;myHandler.sendMessage(msg);textResult = doOcr(bitmapTreated, LANGUAGE);}Message msg2 = new Message();msg2.what = SHOWRESULT;myHandler.sendMessage(msg2);}}).start();}super.onActivityResult(requestCode, resultCode, data);}

负责剪切图片的函数

/*** 调用系统图片编辑进行裁剪*/public void startPhotoCrop(Uri uri) {Intent intent = new Intent("com.android.camera.action.CROP");intent.setDataAndType(uri, "image/*");intent.putExtra("crop", "true");intent.putExtra("scale", true);intent.putExtra(MediaStore.EXTRA_OUTPUT,Uri.fromFile(new File(IMG_PATH, "temp_cropped.jpg")));intent.putExtra("return-data", false);intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());intent.putExtra("noFaceDetection", true); // no face detectionstartActivityForResult(intent, PHOTO_RESULT);}

主要的功能实现函数如上,代码源码贴上:点击打开链接(辛苦手打收两个积分,如果积分不够可在下面留下邮箱,我看到后第一时间发送源码)

因上传源码有大小限制,故吧源码中的语言库删掉了,下载后只需把文章开始的tessdata语言包下的两个文件拷贝进res/raw下即可,如上图。

源码需求的人比较多,现在放在github上免费下载。地址为:https://github.com/cuilonglong/AndroidApp_ImageToText

纯手打,有帮助就回复下,有什么问题也可留言,我们共同讨论下。

转载请注明出处!谢谢!

Android上图片文字识别相关推荐

  1. Android 图片文字识别DEMO(基于百度OCR)

    前言   OCR 是 Optical Character Recognition 的缩写,翻译为光学字符识别,指的是针对印刷体字符,采用光学的方式将纸质文档中的文字转换成为黑白点阵的图像文件,通过识别 ...

  2. Android图片文字识别(阿里OCR接口)

    最近使用了阿里云的OCR文字识别API 先来看看效果 我使用的是通用类文字识别,具体实现过程如下: 1.购买阿里云的通用类文字识别 目前是0元免费的,可以使用500次.购买成功后到->控制台-& ...

  3. Android百度文字识别bitmap,Android集成Tesseract OCR实现图片文字识别

    最近项目需要做图片上的文字识别,在网上找了很久,这方面的知识挺多的,但是很杂.将最近学习到的东西整理一下,仅供参考. 1.Tesseract OCR 介绍我就不说了,自行百度,或者访问:https:/ ...

  4. Android集成百度OCR图片文字识别——总结

    近期由于工作内容的需要,我要给项目集成一个图片文字识别功能,据说百度的不错,所以今天写一个关于百度OCR的集成总结,以便以后再次使用不用去看官方文档. 首先肯定是要在百度管理平台注册账号并登录,然后照 ...

  5. 在手机便签上如何进行图片文字识别?

    有很多时候,我们也许都想要将图片中的文字识别并提取出来使用,例如在看书时想要保存书中的一段话.在工作时需要将文件中的文字提取出来使用等.随着科技的发展,现在我们使用手机软件就能够将图片中的文字识别出来 ...

  6. 吴恩达《Machine Learning》精炼笔记 12:大规模机器学习和图片文字识别 OCR

    作者 | Peter 编辑 | AI有道 系列文章: 吴恩达<Machine Learning>精炼笔记 1:监督学习与非监督学习 吴恩达<Machine Learning>精 ...

  7. Python图片文字识别——Windows下Tesseract-OCR的安装与使用

    Python图片文字识别--Windows下Tesseract-OCR的安装与使用 前言 Windows下Tesseract-OCR的安装与配置 Tesseract-OCR简介与版本选择 tesser ...

  8. 二维码/条码识别、身份证识别、银行卡识别、车牌识别、图片文字识别、黄图识别、驾驶证(驾照)识别

    Scanner 项目地址:shouzhong/Scanner 简介: 二维码/条码识别.身份证识别.银行卡识别.车牌识别.图片文字识别.黄图识别.驾驶证(驾照)识别 更多:作者   提 Bug 标签: ...

  9. 科普---互联网图片 文字识别系统 你造么

    文通互联网图片文字识别系统 你不努力,别人就会超越你! 我明白.不是每一次付出的努力都会得到收货! 但是我始终相信每一次收货.都需要付出努力! 我们的OCR一直在努力改进.提升! 我们在一直按照我们的 ...

  10. 身份证、银行卡、车牌、图片文字识别、黄图识别、驾驶证识别库实现功能

    预览图效果: 原文来自:http://code.662p.com/view/19388.html  ,需要自己去下载就可以了. 使用 依赖 implementation 'com.shouzhong: ...

最新文章

  1. 门户网站建设与运营需要付出更多成本
  2. 【JETSON-NANO】SD卡系统备份克隆
  3. 【Opencv实战】“一岁年龄一岁心,匆匆岁月不由人“这款年龄检测机等你来(附源码)
  4. C语言操作MySQL-----又一个小技巧
  5. react 中组件隐藏显示_React组件开发中常见的陷阱及解决
  6. 95-30-010-Channel-AbstractChannel
  7. 喜大普奔:我的个人博客www.yxmblog.top
  8. 修复数码相片祛除红眼
  9. NodeJS+Express+MongoDB 简单实现数据录入及回显展示【Study笔记】
  10. XPath 简单语法
  11. PCB设计之3W规则和20H原则
  12. matlab如何画波特图,matlab画波特图
  13. VB程序打包,生成安装程序
  14. 推荐系统常用数据集介绍
  15. 自然语言处理(二)基于CNN的新闻文本分类
  16. vcenter中修改vm配置硬盘失败问题分析处理
  17. 艾美智能影库服务器ip,家庭影院播放器;影库 篇一:艾美影库MS-300 到底怎么样?...
  18. 虚拟机与MySQL的安装及配置
  19. exp table oracle,oracle中exp,imp的使用详解
  20. JS的变量,使用strict模式

热门文章

  1. 基于python对B站缓存视频的批量复制,重命名
  2. PowerShell路转粉之造轮子(01)------B站离线缓存简单合并blvm4s
  3. ToString格式转换大全(1)
  4. 【测试】转行软件测试没有项目经历怎么办
  5. 数据库 - BC范式(BCNF)
  6. 单元测试的目的及使用
  7. oracle多表关联索引用法,关联表查询和索引使用的探讨一则
  8. Python通过selenium操作edge浏览器
  9. 必备!万用表使用手册
  10. Markdown中设置图片尺寸及添加图注