如何在android中修复tesseract的UnsatisfiedLinkError

时间:2017-05-09 15:20:04

标签: android ocr tesseract tess-two

我正在尝试使用“tesseract”for android 我正在使用以下库

compile 'org.bytedeco.javacpp-presets:tesseract:3.04.01-1.3'
compile 'org.bytedeco:javacpp:1.3.2'

我有资产中的列车数据。

我的源代码,如果主要活动如下:

package mr.t.mister.mr;


        import android.app.Activity;
import android.content.Intent;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.media.ExifInterface;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

import org.bytedeco.javacpp.lept.PIX;
import org.bytedeco.javacpp.tesseract.TessBaseAPI;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import static org.bytedeco.javacpp.lept.pixRead;
//import com.googlecode.tesseract.android.TessBaseAPI;

public class SimpleAndroidOCRActivity extends Activity {
    public static final String PACKAGE_NAME = "com.datumdroid.android.ocr.simple";
    public static final String DATA_PATH = Environment
            .getExternalStorageDirectory().toString() + "/SimpleAndroidOCR/";

    // You should have the trained data file in assets folder
    // You can get them at:
    // https://github.com/tesseract-ocr/tessdata
    public static final String lang = "eng";

    private static final String TAG = "SimpleAndroidOCR.java";

    protected Button _button;
    // protected ImageView _image;
    protected EditText _field;
    protected String _path;
    protected boolean _taken;

    protected static final String PHOTO_TAKEN = "photo_taken";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        String[] paths = new String[] { DATA_PATH, DATA_PATH + "tessdata/" };

        for (String path : paths) {
            File dir = new File(path);
            if (!dir.exists()) {
                if (!dir.mkdirs()) {
                    Log.v(TAG, "ERROR: Creation of directory " + path + " on sdcard failed");
                    return;
                } else {
                    Log.v(TAG, "Created directory " + path + " on sdcard");
                }
            }

        }

        // lang.traineddata file with the app (in assets folder)
        // You can get them at:
        // http://code.google.com/p/tesseract-ocr/downloads/list
        // This area needs work and optimization
        if (!(new File(DATA_PATH + "tessdata/" + lang + ".traineddata")).exists()) {
            try {

                AssetManager assetManager = getAssets();
                InputStream in = assetManager.open("tessdata/" + lang + ".traineddata");
                //GZIPInputStream gin = new GZIPInputStream(in);
                OutputStream out = new FileOutputStream(DATA_PATH
                        + "tessdata/" + lang + ".traineddata");

                // Transfer bytes from in to out
                byte[] buf = new byte[1024];
                int len;
                //while ((lenf = gin.read(buff)) > 0) {
                while ((len = in.read(buf)) > 0) {
                    out.write(buf, 0, len);
                }
                in.close();
                //gin.close();
                out.close();

                Log.v(TAG, "Copied " + lang + " traineddata");
            } catch (IOException e) {
                Log.e(TAG, "Was unable to copy " + lang + " traineddata " + e.toString());
            }
        }



        // _image = (ImageView) findViewById(R.id.image);
        _field = (EditText) findViewById(R.id.field);
        _button = (Button) findViewById(R.id.button);
        _button.setOnClickListener(new ButtonClickHandler());

        _path = DATA_PATH + "/ocr.jpg";
    }

    public class ButtonClickHandler implements View.OnClickListener {
        public void onClick(View view) {
            Log.v(TAG, "Starting Camera app");
            startCameraActivity();
        }
    }

    // Simple android photo capture:
    // http://labs.makemachine.net/2010/03/simple-android-photo-capture/

    protected void startCameraActivity() {
        File file = new File(_path);
        Uri outputFileUri = Uri.fromFile(file);

        final Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);

        startActivityForResult(intent, 0);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {

        Log.i(TAG, "resultCode: " + resultCode);

        if (resultCode == -1) {
            onPhotoTaken();
        } else {
            Log.v(TAG, "User cancelled");
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        outState.putBoolean(SimpleAndroidOCRActivity.PHOTO_TAKEN, _taken);
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        Log.i(TAG, "onRestoreInstanceState()");
        if (savedInstanceState.getBoolean(SimpleAndroidOCRActivity.PHOTO_TAKEN)) {
            onPhotoTaken();
        }
    }

    protected void onPhotoTaken() {
        _taken = true;

        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inSampleSize = 4;

        Bitmap bitmap = BitmapFactory.decodeFile(_path, options);

        try {
            ExifInterface exif = new ExifInterface(_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) {

                // 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);
            }

            // Convert to ARGB_8888, required by tess
            bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);

        } catch (IOException e) {
            Log.e(TAG, "Couldn't correct orientation: " + e.toString());
        }

        // _image.setImageBitmap( bitmap );

        Log.v(TAG, "Before baseApi");

        TessBaseAPI baseApi = new TessBaseAPI();
        //baseApi.setDebug(true);


        //baseApi.Init()
        baseApi.Init(DATA_PATH, lang);

        PIX image = pixRead(_path);
        //PIX image = pixRead(args.length > 0 ? args[0] : "/usr/src/tesseract/testing/phototest.tif");
        baseApi.SetImage(image);

        String recognizedText = baseApi.GetUTF8Text().getString(); //baseApi.getUTF8Text();

        baseApi.End();

        // You now have the text in recognizedText var, you can do anything with it.
        // We will display a stripped out trimmed alpha-numeric version of it (if lang is eng)
        // so that garbage doesn't make it to the display.

        Log.v(TAG, "OCRED TEXT: " + recognizedText);

        if ( lang.equalsIgnoreCase("eng") ) {
            recognizedText = recognizedText.replaceAll("[^a-zA-Z0-9]+", " ");
        }

        recognizedText = recognizedText.trim();

        if ( recognizedText.length() != 0 ) {
            _field.setText(_field.getText().toString().length() == 0 ? recognizedText : _field.getText() + " " + recognizedText);
            _field.setSelection(_field.getText().toString().length());
        }

        // Cycle done.
    }

    // www.Gaut.am was here
    // Thanks for reading!
}

当我尝试启动tesseract时,App崩溃了。我得到以下的东西:

05-09 20:18:09.187 26906-26906/mr.t.mister.mr E/AndroidRuntime: FATAL EXCEPTION: main
                                                                Process: mr.t.mister.mr, PID: 26906
                                                                java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/mr.t.mister.mr-2/base.apk", zip file "/data/app/mr.t.mister.mr-2/split_lib_dependencies_apk.apk", zip file "/data/app/mr.t.mister.mr-2/split_lib_slice_0_apk.apk", zip file "/data/app/mr.t.mister.mr-2/split_lib_slice_1_apk.apk", zip file "/data/app/mr.t.mister.mr-2/split_lib_slice_2_apk.apk", zip file "/data/app/mr.t.mister.mr-2/split_lib_slice_3_apk.apk", zip file "/data/app/mr.t.mister.mr-2/split_lib_slice_4_apk.apk", zip file "/data/app/mr.t.mister.mr-2/split_lib_slice_5_apk.apk", zip file "/data/app/mr.t.mister.mr-2/split_lib_slice_6_apk.apk", zip file "/data/app/mr.t.mister.mr-2/split_lib_slice_7_apk.apk", zip file "/data/app/mr.t.mister.mr-2/split_lib_slice_8_apk.apk", zip file "/data/app/mr.t.mister.mr-2/split_lib_slice_9_apk.apk"],nativeLibraryDirectories=[/vendor/lib, /system/lib]]] couldn't find "libjnilept.so"
                                                                    at java.lang.Runtime.loadLibrary(Runtime.java:366)
                                                                    at java.lang.System.loadLibrary(System.java:988)
                                                                    at org.bytedeco.javacpp.Loader.loadLibrary(Loader.java:963)
                                                                    at org.bytedeco.javacpp.Loader.load(Loader.java:764)
                                                                    at org.bytedeco.javacpp.Loader.load(Loader.java:671)
                                                                    at org.bytedeco.javacpp.lept.<clinit>(lept.java:10)
                                                                    at java.lang.Class.classForName(Native Method)
                                                                    at java.lang.Class.forName(Class.java:309)
                                                                    at org.bytedeco.javacpp.Loader.load(Loader.java:726)
                                                                    at org.bytedeco.javacpp.Loader.load(Loader.java:671)
                                                                    at org.bytedeco.javacpp.tesseract$TessBaseAPI.<clinit>(tesseract.java:3648)
                                                                    at mr.t.mister.mr.SimpleAndroidOCRActivity.onPhotoTaken(SimpleAndroidOCRActivity.java:214)
                                                                    at mr.t.mister.mr.SimpleAndroidOCRActivity.onActivityResult(SimpleAndroidOCRActivity.java:138)
                                                                    at android.app.Activity.dispatchActivityResult(Activity.java:6192)
                                                                    at android.app.ActivityThread.deliverResults(ActivityThread.java:3570)
                                                                    at android.app.ActivityThread.handleSendResult(ActivityThread.java:3617)
                                                                    at android.app.ActivityThread.access$1300(ActivityThread.java:151)
                                                                    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1352)
                                                                    at android.os.Handler.dispatchMessage(Handler.java:102)
                                                                    at android.os.Looper.loop(Looper.java:135)
                                                                    at android.app.ActivityThread.main(ActivityThread.java:5254)
                                                                    at java.lang.reflect.Method.invoke(Native Method)
                                                                    at java.lang.reflect.Method.invoke(Method.java:372)
                                                                    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
                                                                    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
                                                                 Caused by: java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/mr.t.mister.mr-2/base.apk", zip file "/data/app/mr.t.mister.mr-2/split_lib_dependencies_apk.apk", zip file "/data/app/mr.t.mister.mr-2/split_lib_slice_0_apk.apk", zip file "/data/app/mr.t.mister.mr-2/split_lib_slice_1_apk.apk", zip file "/data/app/mr.t.mister.mr-2/split_lib_slice_2_apk.apk", zip file "/data/app/mr.t.mister.mr-2/split_lib_slice_3_apk.apk", zip file "/data/app/mr.t.mister.mr-2/split_lib_slice_4_apk.apk", zip file "/data/app/mr.t.mister.mr-2/split_lib_slice_5_apk.apk", zip file "/data/app/mr.t.mister.mr-2/split_lib_slice_6_apk.apk", zip file "/data/app/mr.t.mister.mr-2/split_lib_slice_7_apk.apk", zip file "/data/app/mr.t.mister.mr-2/split_lib_slice_8_apk.apk", zip file "/data/app/mr.t.mister.mr-2/split_lib_slice_9_apk.apk"],nativeLibraryDirectories=[/vendor/lib, /system/lib]]] couldn't find "liblept.so"
                                                                    at java.lang.Runtime.loadLibrary(Runtime.java:366)
                                                                    at java.lang.System.loadLibrary(System.java:988)
                                                                    at org.bytedeco.javacpp.Loader.loadLibrary(Loader.java:963)
                                                                    at org.bytedeco.javacpp.Loader.load(Loader.java:752)
                                                                    at org.bytedeco.javacpp.Loader.load(Loader.java:671) 
                                                                    at org.bytedeco.javacpp.lept.<clinit>(lept.java:10) 
                                                                    at java.lang.Class.classForName(Native Method) 
                                                                    at java.lang.Class.forName(Class.java:309) 
                                                                    at org.bytedeco.javacpp.Loader.load(Loader.java:726) 
                                                                    at org.bytedeco.javacpp.Loader.load(Loader.java:671) 
                                                                    at org.bytedeco.javacpp.tesseract$TessBaseAPI.<clinit>(tesseract.java:3648) 
                                                                    at mr.t.mister.mr.SimpleAndroidOCRActivity.onPhotoTaken(SimpleAndroidOCRActivity.java:214) 
                                                                    at mr.t.mister.mr.SimpleAndroidOCRActivity.onActivityResult(SimpleAndroidOCRActivity.java:138) 
                                                                    at android.app.Activity.dispatchActivityResult(Activity.java:6192) 
                                                                    at android.app.ActivityThread.deliverResults(ActivityThread.java:3570) 
                                                                    at android.app.ActivityThread.handleSendResult(ActivityThread.java:3617) 
                                                                    at android.app.ActivityThread.access$1300(ActivityThread.java:151) 
                                                                    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1352) 
                                                                    at android.os.Handler.dispatchMessage(Handler.java:102) 
                                                                    at android.os.Looper.loop(Looper.java:135) 
                                                                    at android.app.ActivityThread.main(ActivityThread.java:5254) 
                                                                    at java.lang.reflect.Method.invoke(Native Method) 
                                                                    at java.lang.reflect.Method.invoke(Method.java:372) 
                                                                    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903) 
                                                                    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698) 
05-09 20:18:09.282 26906-26919/mr.t.mister.mr I/art: Background partial concurrent mark sweep GC freed 798(72KB) AllocSpace objects, 2(91KB) LOS objects, 41% free, 1438KB/2MB, paused 14.815ms total 39.575ms

2 个答案:

答案 0 :(得分:0)

当Android无法获取.so库时会产生不满意的链接错误。

确保所有.so都在相应的文件夹中。以下一个或几个 - &gt; https://developer.android.com/ndk/guides/abis.html?hl=es

src
---main
------java
---------jnilibs
------------armeabi 
------------arm64-v8a
------------...

如果您的设备的处理器与您定义的某个处理器不匹配,也可以尝试解决该问题。

您可以强制您的应用使用一组定义的abis修改build.gradle

defaultConfig {
    ....
    ndk.abiFilters 'armeabi', 'arm64-v8a'
}

答案 1 :(得分:0)

我遇到了同样的问题。当我使用 * 包含如下所有依赖项时,它消失了。

import org.bytedeco.javacpp.*;
import org.bytedeco.leptonica.*;
import org.bytedeco.tesseract.*;
import static org.bytedeco.leptonica.global.lept.*;
import static org.bytedeco.tesseract.global.tesseract.*;