经过两个星期的试错,终于成功的在android平台上识别出图片。
我的完整代码可以从 这儿 下载。这是一个完整工程。若要使用,请详细查看下面的说明。
代码讲解:
我使用的是 黑暗伯爵 已经编译好tess-two.zip,里面有已经编译好的so文件(linux下的类似于dll文件的动态库)和jar文件。
使用方法:
1.解压
2.将googlecode文件夹(从其他地方下载)拷贝到自己工程里的com文件夹内
3.将里面的libs文件夹拷贝到工程根目录下
4.将tess-two.tesseract3.01-leptonica1.68-LibJPEG6b.jar包也直接拷贝到工程的libs里面,然后再导入这个jar
然后,我的测试代码是从 这个博客 上拷贝的。不过我修改了几点,否则会报错。下面是改正过后的代码,如果不对,估计您还要自己再改改。
public class SliderTessActivity extends Activity { private static final String TAG = "MainActivity ..."; private static final String TESSBASE_PATH = "/mnt/sdcard/tesseract/"; private static final String DEFAULT_LANGUAGE = "eng"; private static final String IMAGE_PATH = "/mnt/sdcard/ocr.jpg"; private static final String EXPECTED_FILE = TESSBASE_PATH + "tessdata/" + DEFAULT_LANGUAGE + ".traineddata"; private TessBaseAPI service; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); testOcr(); } public void testOcr(){ mHandler.post(new Runnable() { @Override public void run() { Log.d(TAG, "begin>>>>>>>"); ocr(); //test(); } }); } public void test(){ // First, make sure the eng.traineddata file exists. /*assertTrue("Make sure that you've copied " + DEFAULT_LANGUAGE + ".traineddata to " + EXPECTED_FILE, new File(EXPECTED_FILE).exists());*/ final TessBaseAPI baseApi = new TessBaseAPI(); baseApi.init(TESSBASE_PATH, DEFAULT_LANGUAGE); final Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher); //digits is a .jpg image I found in one of the issues here. ImageView img = (ImageView) findViewById(R.id.image); img.setImageBitmap(bmp);//I can see the ImageView. So we know that it should work if I sent it to the setImage() baseApi.setImage(bmp); Log.v("Kishore","Kishore:Working");//This statement is never reached. Futhermore, on putting some more Log.v commands in the setImage function, I found out that the native function nativeSetImagePix is never accessed. I have attached the Logcat output below to show that it is not accessed. String outputText = baseApi.getUTF8Text(); Log.v("Kishore","Kishore:"+outputText); baseApi.end(); bmp.recycle(); } protected void ocr() { BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = 2; Bitmap bitmap = BitmapFactory.decodeFile(IMAGE_PATH, options); Log.d("nimei", "---in ocr() before try--"); try { Log.v(TAG, "not in the exception"); ExifInterface exif = new ExifInterface(IMAGE_PATH); int exifOrientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL); Log.v(TAG, "Orient: " + exifOrientation); int rotate = 0; switch (exifOrientation) { case ExifInterface.ORIENTATION_ROTATE_90: rotate = 90; break; case ExifInterface.ORIENTATION_ROTATE_180: rotate = 180; break; case ExifInterface.ORIENTATION_ROTATE_270: rotate = 270; break; } Log.v(TAG, "Rotation: " + rotate); // if (rotate != 0) { //这儿必须要注释掉,否则会报错 什么 ARGB_8888之类的 // Getting width & height of the given image. int w = bitmap.getWidth(); int h = bitmap.getHeight(); // Setting pre rotate Matrix mtx = new Matrix(); mtx.preRotate(rotate); // Rotating Bitmap bitmap = Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, false); // tesseract req. ARGB_8888 bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true); // } //这儿必须要注释掉,否则会报错 什么 ARGB_8888之类的 } catch (IOException e) { Log.e(TAG, "Rotate or coversion failed: " + e.toString()); Log.v(TAG, "in the exception"); } ImageView iv = (ImageView) findViewById(R.id.image); iv.setImageBitmap(bitmap); iv.setVisibility(View.VISIBLE); Log.v(TAG, "Before baseApi"); TessBaseAPI baseApi = new TessBaseAPI(); baseApi.setDebug(true); baseApi.init(TESSBASE_PATH, DEFAULT_LANGUAGE); baseApi.setImage(bitmap); String recognizedText = baseApi.getUTF8Text(); baseApi.end(); Log.v(TAG, "OCR Result: " + recognizedText); // clean up and show if (DEFAULT_LANGUAGE.equalsIgnoreCase("eng")) { recognizedText = recognizedText.replaceAll("[^a-zA-Z0-9]+", " "); } if (recognizedText.length() != 0) { ((TextView) findViewById(R.id.field)).setText(recognizedText.trim()); } } private Handler mHandler = new Handler(){ public void handleMessage(android.os.Message msg) { }; }; }
说明:
代码工作前提:
1.新建HelloWorld项目,打开helloworldActivity.java,全选,将我们的代码全部复制进去,保存。
2.import之类的错误,自己按照MyEclipse的提示自己加。(鼠标放在出错的位置悬停足够时间,出现弹出框后选择 “import”,如果两个import尽量选android开头的)
3.与代码配套的main.xml文件也要修改一下
main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" /> <ImageView android:id="@+id/image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_launcher" /> <TextView android:id="@+id/field" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="" /> </LinearLayout>
4./mnt/sdcard/tesseract/tessdata目录下要有xxx.traineddata文件,代码中是 eng.traineddata(识别英文)。这个文件我会提供下载,您要把这个文件拷贝到模拟器的SD卡中。(window -> show view -> other -> File Explorer然后可以直接拖拽:选中tessdata文件夹将文件eng.traineddata拖进tessdata文件夹)
5./mnt/sdcard/ocr.jpg其中ocr.jpg是要测试的图片,复杂的没试过,只试过自己用画图直接写的几个单词,可以正确识别。
6.代码中有很多我加上的调试代码,我没有去掉,方便大家定位错误信息。(查看方式:Window-show view-other-Logcat)
遇到的错误:
当我从项目外部导入jar时,运行总是出现“Conversion to Dalvik format failed with error 1”的错误
后来,将那个jar包索性直接拷贝到了libs目录下,然后在Buile Path中删掉了那个引入的jar包,哎,反而没错了,真不知道为什么。
另外注明我的系统环境:
PC :windows7
IDE:MyEclispe 8.6
android SDK: 2.2
jdk :1.6
还有什么大家可以问哈。
其他的我暂时也相不出什么了,希望大家都能调试通过!
参考:
黑暗伯爵的 tess-two.zip http://www.cnblogs.com/hangxin1940/archive/2012/01/13/2321507.html
slider 的 测试代码 http://www.cnblogs.com/slider/archive/2012/03/21/2409888.html#commentform
另外,还有国外的链接。多半是讲解如何从官网上git包,然后又怎样在linux的android环境下用ndk怎样编译,编译好又如何设置Is Library,总之比较繁琐,但也体现出专心和细致。
注:自己重新编译比较复杂,必须要在linux环境下,并且要是用ndk,ant等工具。我一一安装后,又由于对ndk的最新版本不支持原因无法编译正确(可以编译但是不可用)。如果时间充分,可以研究,时间不多,建议使用 黑暗伯爵 的 tess-two.zip(我成功识别图片)
http://wolfpaulus.com/journal/android-journal/android-and-ocr
http://gaut.am/making-an-ocr-android-app-using-tesseract/
http://www.harshadura.net/2011/12/making-simple-ocr-android-app-using.html
http://rmtheis.wordpress.com/2011/08/06/using-tesseract-tools-for-android-to-create-a-basic-ocr-app/
后记:
这里只是识别图片,我是要做一个拍照取词的词典,所以还有很多事情要做。
补:
没想到一年之后的毕业设计也要做一个相关的课题:利用数字图像和模式识别来识别车牌号,这次估计要尝试去理解算法了。我还是很想在图像识别领域做些事情的,希望大家一起进步!
补(编辑时间:2013.01.30):
最近看到一个JAVA语言利用开源OCR引擎Tesseract 3.0识别中文的博客文章,看效果图发现代码效果相当的优秀。当然也很容易发现它是识别的图片,并且因该博主没有隐藏文章中的换行符号导致频繁出现换行后冒出一个误识别的错字。下面是该博客链接:
http://blog.csdn.net/zhoushuyan/article/details/5948289#1567946