How can I use larger images in TensorFlow OCR in Android?

I’m working on a Java Android project that needs to OCR bitmaps with width=1887 and height=1061 .

I’ve downloaded the recommended git repo with its Kotlin code. Kotlin is not my language though, so I’m struggling to figure things out in it. But I was able to get that sample running and working fine via Android Studio on my Android device.

I was able to use the Kotlin classes to implement OCR in my Java project as well. However, the results were terribly subpar (words run together, missing words and letters, confusing order) and very, very, very slow (30-40 seconds).

I suspect these problems are at least partly because the Kotlin code from the Git repo appears to resize my bitmap from 1887x1061 to 200x31 for text recognition, and elsewhere appears to resize it to 320x320 for text detection.

My initial images are screenshots that should need no rotation and use standard fonts, so I would expect fairly good results right up front. You can see more information about what I’ve done and the results I’m getting in this Stack Overflow post.

How can I get better TensorFlow OCR results for my bitmaps and also speed up the process?

In answer, I would really appreciate code samples, or links to code samples. Thanks in advance!

You might want to try with a solution that is more ready out of the box like Tesseract:

Thanks for the reply @saudet . I have already set up Tesseract in this project. I’ve also set up Google’s MLKit. They both work wonderfully.

Except that after about 500 OCRs, Tesseract causes the OS to crash. No apparent RAM buildup or odd spikes of any kind that I can see. I haven’t yet been able to figure out how to prevent this.

And Google MLKit is only available on devices that come with the Play Store.

So I’m looking for an alternative to those two options. Figured I’d try this.

Is TensorFlow OCR not something that can just be plugged in to my app (possibly with a few minor tweaks)?

And how does your version of Tesseract compare to TessTwo? That’s the one everyone seemed to be referencing and pointing to (and that’s the one crashing my OS).

@saudet I’m having trouble figuring out how to use your Tesseract library in my Java Android app. Given that you described it as “ready out of the box,” is there a simple step-by-step guide somewhere?

  1. I don’t know what implementation lines to have in my build.gradle file, and I can’t seem to get this right by guessing.
  2. I don’t know what external code files or libraries I may need to manually download, or where exactly to put them in my app.
  3. I don’t know what to import in the Java code file where I actually call TessBaseAPI, and I can’t seem to get this right by guessing either.

Can you point me somewhere that will plainly answer these questions? Thanks!

There’s a working sample project here if that’s what you’re looking for:

@saudet I cloned and ran the JavaCV-android-example that you linked to. It ran just fine as far as I could tell. But it doesn’t appear to have anything at all to do with OCR, which is what I’m looking for, as I said in the OP. Maybe I’m missing something?

I tried to run the tesseract-ocr sample in the same repo. But I loaded it into Android Studio, with my Android phone connected, and there is no option to run the app. Instead it asks me to add a configuration. But what’s the proper configuration for this app? Again, maybe I’m missing something?

Next I tried javacv-android-recognize. As soon as I opened that one (unchanged, just a fresh clone from GIT) in Android Studio I saw build errors:

* Exception is:
org.gradle.internal.event.ListenerNotificationException: Failed to notify build listener.
	at org.gradle.internal.event.AbstractBroadcastDispatch.dispatch(AbstractBroadcastDispatch.java:86)
	at org.gradle.internal.event.BroadcastDispatch$CompositeDispatch.dispatch(BroadcastDispatch.java:324)
	at org.gradle.internal.event.BroadcastDispatch$CompositeDispatch.dispatch(BroadcastDispatch.java:234)
	at org.gradle.internal.event.ListenerBroadcast.dispatch(ListenerBroadcast.java:140)
	at org.gradle.internal.event.ListenerBroadcast.dispatch(ListenerBroadcast.java:37)
	at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
	at com.sun.proxy.$Proxy16.buildFinished(Unknown Source)
	at org.gradle.initialization.DefaultGradleLauncher.finishBuild(DefaultGradleLauncher.java:146)
	at org.gradle.initialization.DefaultGradleLauncher.finishBuild(DefaultGradleLauncher.java:114)
	at org.gradle.internal.invocation.GradleBuildController$2.call(GradleBuildController.java:88)
	at org.gradle.internal.invocation.GradleBuildController$2.call(GradleBuildController.java:84)
	at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:152)
	at org.gradle.internal.invocation.GradleBuildController.doBuild(GradleBuildController.java:100)
	at org.gradle.internal.invocation.GradleBuildController.configure(GradleBuildController.java:84)
	at org.gradle.tooling.internal.provider.runner.ClientProvidedBuildActionRunner.run(ClientProvidedBuildActionRunner.java:65)
	at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35)
	at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35)
	at org.gradle.tooling.internal.provider.ValidatingBuildActionRunner.run(ValidatingBuildActionRunner.java:32)
	at org.gradle.launcher.exec.RunAsBuildOperationBuildActionRunner$1.run(RunAsBuildOperationBuildActionRunner.java:43)
	at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:336)
	at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:328)
	at org.gradle.internal.progress.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:197)
	at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:107)
	at org.gradle.launcher.exec.RunAsBuildOperationBuildActionRunner.run(RunAsBuildOperationBuildActionRunner.java:40)
	at org.gradle.tooling.internal.provider.SubscribableBuildActionRunner.run(SubscribableBuildActionRunner.java:51)
	at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:45)
	at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:29)
	at org.gradle.launcher.exec.BuildTreeScopeBuildActionExecuter.execute(BuildTreeScopeBuildActionExecuter.java:39)
	at org.gradle.launcher.exec.BuildTreeScopeBuildActionExecuter.execute(BuildTreeScopeBuildActionExecuter.java:25)
	at org.gradle.tooling.internal.provider.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:71)
	at org.gradle.tooling.internal.provider.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:45)
	at org.gradle.tooling.internal.provider.ServicesSetupBuildActionExecuter.execute(ServicesSetupBuildActionExecuter.java:51)
	at org.gradle.tooling.internal.provider.ServicesSetupBuildActionExecuter.execute(ServicesSetupBuildActionExecuter.java:32)
	at org.gradle.tooling.internal.provider.GradleThreadBuildActionExecuter.execute(GradleThreadBuildActionExecuter.java:36)
	at org.gradle.tooling.internal.provider.GradleThreadBuildActionExecuter.execute(GradleThreadBuildActionExecuter.java:25)
	at org.gradle.tooling.internal.provider.ParallelismConfigurationBuildActionExecuter.execute(ParallelismConfigurationBuildActionExecuter.java:43)
	at org.gradle.tooling.internal.provider.ParallelismConfigurationBuildActionExecuter.execute(ParallelismConfigurationBuildActionExecuter.java:29)
	at org.gradle.tooling.internal.provider.StartParamsValidatingActionExecuter.execute(StartParamsValidatingActionExecuter.java:64)
	at org.gradle.tooling.internal.provider.StartParamsValidatingActionExecuter.execute(StartParamsValidatingActionExecuter.java:29)
	at org.gradle.tooling.internal.provider.SessionFailureReportingActionExecuter.execute(SessionFailureReportingActionExecuter.java:55)
	at org.gradle.tooling.internal.provider.SessionFailureReportingActionExecuter.execute(SessionFailureReportingActionExecuter.java:42)
	at org.gradle.tooling.internal.provider.SetupLoggingActionExecuter.execute(SetupLoggingActionExecuter.java:58)
	at org.gradle.tooling.internal.provider.SetupLoggingActionExecuter.execute(SetupLoggingActionExecuter.java:33)
	at org.gradle.launcher.daemon.server.exec.ExecuteBuild.doBuild(ExecuteBuild.java:67)
	at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
	at org.gradle.launcher.daemon.server.exec.WatchForDisconnection.execute(WatchForDisconnection.java:37)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
	at org.gradle.launcher.daemon.server.exec.ResetDeprecationLogger.execute(ResetDeprecationLogger.java:26)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
	at org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon.execute(RequestStopIfSingleUsedDaemon.java:34)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
	at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:74)
	at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:72)
	at org.gradle.util.Swapper.swap(Swapper.java:38)
	at org.gradle.launcher.daemon.server.exec.ForwardClientInput.execute(ForwardClientInput.java:72)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
	at org.gradle.launcher.daemon.server.exec.LogAndCheckHealth.execute(LogAndCheckHealth.java:55)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
	at org.gradle.launcher.daemon.server.exec.LogToClient.doBuild(LogToClient.java:62)
	at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
	at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:82)
	at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
	at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy$1.run(StartBuildOrRespondWithBusy.java:50)
	at org.gradle.launcher.daemon.server.DaemonStateCoordinator$1.run(DaemonStateCoordinator.java:297)
	at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
	at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
	at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
Caused by: java.lang.NoClassDefFoundError: org/gradle/api/tasks/testing/AbstractTestTask
	at org.jetbrains.plugins.gradle.tooling.builder.ExternalProjectBuilderImpl.getTestTasks(ExternalProjectBuilderImpl.groovy:179)
	at org.jetbrains.plugins.gradle.tooling.builder.ExternalProjectBuilderImpl.doBuild(ExternalProjectBuilderImpl.groovy:117)
	at org.jetbrains.plugins.gradle.tooling.builder.ExternalProjectBuilderImpl.buildAll(ExternalProjectBuilderImpl.groovy:76)
	at org.jetbrains.plugins.gradle.tooling.internal.ExtraModelBuilder.buildAll(ExtraModelBuilder.java:107)
	at org.jetbrains.plugins.gradle.tooling.internal.ExtraModelBuilder.buildAll(ExtraModelBuilder.java:76)
	at org.gradle.tooling.internal.provider.runner.DefaultBuildController.getModel(DefaultBuildController.java:55)
	at org.gradle.tooling.internal.consumer.connection.BuildControllerWithoutParameterSupport.getModel(BuildControllerWithoutParameterSupport.java:53)
	at org.gradle.tooling.internal.consumer.connection.UnparameterizedBuildController.getModel(UnparameterizedBuildController.java:113)
	at org.gradle.tooling.internal.consumer.connection.BuildControllerWithoutParameterSupport.getModel(BuildControllerWithoutParameterSupport.java:48)
	at org.gradle.tooling.internal.consumer.connection.UnparameterizedBuildController.findModel(UnparameterizedBuildController.java:97)
	at org.gradle.tooling.internal.consumer.connection.BuildControllerWithoutParameterSupport.findModel(BuildControllerWithoutParameterSupport.java:32)
	at org.gradle.tooling.internal.consumer.connection.UnparameterizedBuildController.findModel(UnparameterizedBuildController.java:81)
	at org.gradle.tooling.internal.consumer.connection.BuildControllerWithoutParameterSupport.findModel(BuildControllerWithoutParameterSupport.java:32)
	at org.jetbrains.plugins.gradle.model.ProjectImportAction$MyBuildController.findModel(ProjectImportAction.java:594)
	at org.jetbrains.plugins.gradle.model.ProjectImportAction$MyBuildController.findModel(ProjectImportAction.java:615)
	at org.jetbrains.plugins.gradle.model.ClassSetImportModelProvider.populateBuildModels(ClassSetImportModelProvider.java:27)
	at org.jetbrains.plugins.gradle.model.ProjectImportAction.addBuildModels(ProjectImportAction.java:371)
	at org.jetbrains.plugins.gradle.model.ProjectImportAction.execute(ProjectImportAction.java:132)
	at org.jetbrains.plugins.gradle.model.ProjectImportAction.execute(ProjectImportAction.java:42)
	at org.gradle.tooling.internal.consumer.connection.InternalBuildActionAdapter.execute(InternalBuildActionAdapter.java:55)
	at org.gradle.tooling.internal.provider.runner.ClientProvidedBuildActionRunner.buildResult(ClientProvidedBuildActionRunner.java:76)
	at org.gradle.tooling.internal.provider.runner.ClientProvidedBuildActionRunner.access$000(ClientProvidedBuildActionRunner.java:38)
	at org.gradle.tooling.internal.provider.runner.ClientProvidedBuildActionRunner$1.buildFinished(ClientProvidedBuildActionRunner.java:57)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
	at org.gradle.internal.event.DefaultListenerManager$ListenerDetails.dispatch(DefaultListenerManager.java:371)
	at org.gradle.internal.event.DefaultListenerManager$ListenerDetails.dispatch(DefaultListenerManager.java:353)
	at org.gradle.internal.event.AbstractBroadcastDispatch.dispatch(AbstractBroadcastDispatch.java:58)
	at org.gradle.internal.event.DefaultListenerManager$EventBroadcast$ListenerDispatch.dispatch(DefaultListenerManager.java:341)
	at org.gradle.internal.event.DefaultListenerManager$EventBroadcast$ListenerDispatch.dispatch(DefaultListenerManager.java:328)
	at org.gradle.internal.event.AbstractBroadcastDispatch.dispatch(AbstractBroadcastDispatch.java:42)
	at org.gradle.internal.event.BroadcastDispatch$SingletonDispatch.dispatch(BroadcastDispatch.java:230)
	at org.gradle.internal.event.BroadcastDispatch$SingletonDispatch.dispatch(BroadcastDispatch.java:149)
	at org.gradle.internal.event.AbstractBroadcastDispatch.dispatch(AbstractBroadcastDispatch.java:58)
	... 69 more
Caused by: java.lang.ClassNotFoundException: org.gradle.api.tasks.testing.AbstractTestTask
	... 103 more

I would love it if I could get some meaningful OCR sample to run. Which sample is supposed to have OCR functionality? If it’s one of the three I tried, how do I get it to actually OCR an image?

Thanks again!

The sample code for OCR is on the original page I gave you:

But you said you didn’t know how to use Gradle, so I gave you a working example project:

So, put that together. One plus one makes two.

@saudet I created a whole new Android Java project with one blank activity. Trying to add one and one, like you said, and I’m getting the following error:
java.lang.UnsatisfiedLinkError: dlopen failed: library "libjnilept.so" not found

Here is my build.gradle:

plugins {
    id 'com.android.application'
}

android {
    namespace 'com.example.bytedecoocrtest'
    compileSdk 33

    defaultConfig {
        applicationId "com.example.bytedecoocrtest"
        minSdk 21
        targetSdk 33
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    buildFeatures {
        viewBinding true
    }
}

configurations {
    javacpp
}

dependencies {

    implementation 'androidx.appcompat:appcompat:1.6.1'
    implementation 'com.google.android.material:material:1.8.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
    implementation 'androidx.navigation:navigation-fragment:2.4.1'
    implementation 'androidx.navigation:navigation-ui:2.4.1'
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'

    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.appcompat:appcompat:1.3.0'
    implementation group: 'org.bytedeco', name: 'javacv', version: '1.5.6'
    javacpp group: 'org.bytedeco', name: 'openblas-platform', version: '0.3.17-1.5.6'
    javacpp group: 'org.bytedeco', name: 'opencv-platform', version: '4.5.3-1.5.6'
    javacpp group: 'org.bytedeco', name: 'ffmpeg-platform', version: '4.4-1.5.6'
}

Here is my MainActivity.java:

package com.example.bytedecoocrtest;

import android.net.Uri;
import android.os.Bundle;
import com.google.android.material.snackbar.Snackbar;
import androidx.appcompat.app.AppCompatActivity;
import android.view.View;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;
import androidx.navigation.ui.AppBarConfiguration;
import androidx.navigation.ui.NavigationUI;
import com.example.bytedecoocrtest.databinding.ActivityMainBinding;
import android.view.Menu;
import android.view.MenuItem;
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.*;
import java.io.IOException;

public class MainActivity extends AppCompatActivity {

    private AppBarConfiguration appBarConfiguration;
    private ActivityMainBinding binding;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        setSupportActionBar(binding.toolbar);

        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main);
        appBarConfiguration = new AppBarConfiguration.Builder(navController.getGraph()).build();
        NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);

        binding.fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });

        doOcr();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    public boolean onSupportNavigateUp() {
        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main);
        return NavigationUI.navigateUp(navController, appBarConfiguration)
                || super.onSupportNavigateUp();
    }

    public void doOcr()
    {
        BytePointer outText;
        try {
            TessBaseAPI api = new TessBaseAPI();
            // Initialize tesseract-ocr with English, without specifying tessdata path
            if (api.Init(null, "eng") != 0) {
                System.err.println("Could not initialize tesseract.");
                System.exit(1);
            }

            // Open input image with leptonica library
            // https://stackoverflow.com/questions/4820816/how-to-get-uri-from-an-asset-file
            Uri uri = Uri.parse("android.resource://"+getPackageName()+"/ocr-01.jpg");
            PIX image = pixRead(String.valueOf(uri));
            api.SetImage(image);
            // Get OCR result
            outText = api.GetUTF8Text();
            System.out.println("OCR output:\n" + outText.getString());

            // Destroy used object and release memory
            api.End();
            outText.deallocate();
            pixDestroy(image);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

Any suggestions on how to resolve the error? Or other things I will need to alter to get the sample code to run? Thanks again.

As mentioned on the first page, we need to add a dependency on tesseract-platform to get the native binaries:

@saudet I added this line to my build.gradle file:
javacpp group: 'org.bytedeco', name: 'tesseract-platform', version: '5.3.1-1.5.9-SNAPSHOT'

But I continued to get the same error running the app:
java.lang.UnsatisfiedLinkError: dlopen failed: library "libjnilept.so" not found

Instead of Android Studio, I decided to create an empty directory and put in the pom.xml file and the BasicExample.java file, exactly as they are in your documentation, along with the image file I’m trying to test. I then had to install Maven. I then ran the command from inside that new directory:
mvn compile exec:java -Dexec.args="ocr-01.jpg"

I got the following warning:
The POM for org.bytedeco:tesseract-platform:jar:5.3.1-1.5.9-SNAPSHOT is missing, no dependency information available

I also got the following error:
Failed to execute goal on project BasicExample: Could not resolve dependencies for project org.bytedeco.tesseract:BasicExample:jar:1.5.9-SNAPSHOT: The following artifacts could not be resolved: org.bytedeco:tesseract-platform:jar:5.3.1-1.5.9-SNAPSHOT (absent): Could not find artifact org.bytedeco:tesseract-platform:jar:5.3.1-1.5.9-SNAPSHOT

I adjusted the version numbers from 5.3.1-1.5.9-SNAPSHOT to 5.2.0-1.5.8 and tried again. This time I got the following errors:

BasicExample.java:[4,44] cannot find symbol
symbol:   class lept
location: package org.bytedeco.leptonica.global

BasicExample.java:[19,21] cannot find symbol
symbol:   method pixRead(java.lang.String)
location: class BasicExample

BasicExample.java:[28,9] cannot find symbol
symbol:   method pixDestroy(org.bytedeco.leptonica.PIX)
location: class BasicExample

I went back to Android Studio and changed my new build.gradle line to:
javacpp group: 'org.bytedeco', name: 'tesseract-platform', version: '5.2.0-1.5.8'

But I still got the following error:
java.lang.UnsatisfiedLinkError: dlopen failed: library "libjnilept.so" not found

I went back to the pom.xml file and added the following dependencies, hoping maybe they would help:

<dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>openblas-platform</artifactId>
    <version>0.3.17-1.5.6</version>
</dependency>
<dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>opencv-platform</artifactId>
    <version>4.5.3-1.5.6</version>
</dependency>
<dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>ffmpeg-platform</artifactId>
    <version>4.4-1.5.6</version>
</dependency>

That changed nothing. I added:

<dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>leptonica</artifactId>
    <version>1.78.0-1.5.1</version>
</dependency>

That changed the error to this:
Failed to execute goal org.codehaus.mojo:exec-maven-plugin:3.1.0:java (default-cli) on project BasicExample: An exception occurred while executing the Java class. null: ExceptionInInitializerError: Type org.bytedeco.leptonica.presets.leptonica not present

I added this:

<dependency>
    <groupId>org.bytedeco.javacpp-presets</groupId>
    <artifactId>leptonica</artifactId>
    <version>1.77.0-1.4.4</version>
</dependency>

But the error didn’t change.

I switched the version number of one of the dependencies:

<dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>leptonica</artifactId>
    <version>1.82.0-1.5.8</version>
</dependency>

That changed the error to this:
Error opening data file ./eng.traineddata

I copied over my traineddata file from my Android Studio project to the terminal-executed Maven project and ran it again. Then I got these warnings:

Versions of org.bytedeco:javacpp:1.5.6 and org.bytedeco:leptonica:1.82.0-1.5.8 do not match.
Versions of org.bytedeco:javacpp:1.5.6 and org.bytedeco:tesseract:5.2.0-1.5.8 do not match.
Parameter not found: enable_new_segsearch

And I got this error:
Failed to execute goal org.codehaus.mojo:exec-maven-plugin:3.1.0:java (default-cli) on project BasicExample: An exception occurred while executing the Java class. org/bytedeco/leptonica/global/lept: org.bytedeco.leptonica.global.lept

I really don’t know what versions of your code are compatible with what versions of your code, and I don’t know what libraries of yours need to be included that aren’t, and I’m really just taking shots in the dark with this.

Do you have any more suggestions on making the sample OCR code work? Preferably in an Android Studio app using Gradle?

Thanks – I really appreciate your help!

Unless you have a reason to use the snapshots, I recommend just using the latest release version, which is 1.5.8. Also, don’t try to mix versions like you’re trying to do with 1.4.4, 1.5.1, 1.5.6, and 1.5.8, unless again you have a really good reason to try to do that Just set everything to 1.5.8, that’s the latest and greatest. And if you really want to try to use the snapshots, you’ll need to add the snapshot repository to your build file as explained here:

http://bytedeco.org/builds/

That means you need to download that file from the data repository given again here:

@saudet I tried this:

<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.bytedeco.tesseract</groupId>
    <artifactId>BasicExample</artifactId>
    <version>1.5.8</version>
    <properties>
        <exec.mainClass>BasicExample</exec.mainClass>
    </properties>
    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.bytedeco -->
        <dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>openblas-platform</artifactId>
            <version>0.3.21-1.5.8</version>
        </dependency>
        <dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>opencv-platform</artifactId>
            <version>4.6.0-1.5.8</version>
        </dependency>
        <dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>ffmpeg-platform</artifactId>
            <version>5.1.2-1.5.8</version>
        </dependency>
        <dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>tesseract-platform</artifactId>
            <version>5.2.0-1.5.8</version>
        </dependency>
        <dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>leptonica-platform</artifactId>
            <version>1.82.0-1.5.8</version>
        </dependency>
    </dependencies>
    <build>
        <sourceDirectory>.</sourceDirectory>
    </build>
</project>

I’m getting the following errors:

Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.10.1:compile (default-compile) on project BasicExample: Compilation failure: Compilation failure: 
BasicExample.java:[5,44] cannot find symbol
symbol:   class lept
location: package org.bytedeco.leptonica.global

BasicExample.java:[20,21] cannot find symbol
symbol:   method pixRead(java.lang.String)
location: class BasicExample

BasicExample.java:[29,9] cannot find symbol
symbol:   method pixDestroy(org.bytedeco.leptonica.PIX)
location: class BasicExample

Any other suggestions?

Thanks!

Looks like I forgot to update the example in the README.md file. Use this one:

@saudet Thank you so much! The sample works now! Hopefully I can take it from here!

1 Like