Search code examples
androidandroid-studioandroid-ndktesseractandroid.mk

Adding Tesseract and Opencv to Android.mk (Android Studio)


I followed the instructions from here and added OpenCV successfully. But I've been trying to add tesseract to the Android.mk as well, for a few days now, and haven't been able to do it.

I have an android.cpp that uses tesseract so I have to include the dependency in my Android.mk . I found this post that had almost the exact problem and he solved it importing libtess.so and liblept.so files into Android.mk, but didn't explain how to do that, so I looked and found this post that shows how to link prebuilt libraries. So based on that I tried this Android.mk:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE := liblept
LOCAL_SRC_FILES := ../libs/$(TARGET_ARCH_ABI)/liblept.so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/../../../../tess-two/jni
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := libtess
LOCAL_SRC_FILES := ../libs/$(TARGET_ARCH_ABI)/libtess.so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/../../../../tess-two/jni
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
OPENCV_PACKAGE_DIR:= /Users/danielsierraf/Documents/OpenCV-2.4.10-android-sdk/sdk
OPENCV_CAMERA_MODULES := off
include $(OPENCV_PACKAGE_DIR)/native/jni/OpenCV.mk

LOCAL_MODULE    := run_detection
LOCAL_SHARED_LIBRARIES := libtess
LOCAL_SRC_FILES := text_detect.cpp android.cpp
LOCAL_LDLIBS    += -landroid -llog -ldl

include $(BUILD_SHARED_LIBRARY)

And got this output:

[armeabi-v7a] Prebuilt       : liblept.so <= src/main/jni/../libs/armeabi-v7a/
[armeabi-v7a] Install        : liblept.so => src/main/jniLibs/armeabi-v7a/liblept.so
[armeabi-v7a] Compile++ thumb: run_detection <= text_detect.cpp
In file included from src/main/jni/text_detect.h:4:0,
                 from src/main/jni/text_detect.cpp:10:
src/main/jni/../../../../tess-two/jni/com_googlecode_tesseract_android/src/api/baseapi.h:32:22: fatal error: platform.h: No such file or directory
 #include "platform.h"
                      ^
compilation terminated.

So I guess is not linking libtess correctly, and if you look closely, it doesn't ever install libtess.so, it looks like it installs liblept.so, and then jumps to text_detect.cpp, ignoring this part:

include $(CLEAR_VARS)
LOCAL_MODULE := libtess
LOCAL_SRC_FILES := ../libs/$(TARGET_ARCH_ABI)/libtess.so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/../../../../tess-two/jni
include $(PREBUILT_SHARED_LIBRARY)

So I tried to force it to install liblept and libtess completely before proceeding by putting it in different files. So I put the last part of the file in a different Android.mk in another folder and tried include $(call all-subdir-makefiles), and then it installs libtess and liblept completely, but ignores the call all-subdir-makefiles.

new jni folder structure:

Android.mk
Application.mk
text_detect/
     Android.mk
     android.cpp
     text_detect.cpp
     text_detect.h

Android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE := liblept
LOCAL_SRC_FILES := ../libs/$(TARGET_ARCH_ABI)/liblept.so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/../../../../tess-two/jni
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := libtess
LOCAL_SRC_FILES := ../libs/$(TARGET_ARCH_ABI)/libtess.so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/../../../../tess-two/jni
include $(PREBUILT_SHARED_LIBRARY)

include $(call all-subdir-makefiles)

textdetect/Android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

OPENCV_PACKAGE_DIR:= /Users/danielsierraf/Documents/OpenCV-2.4.10-android-sdk/sdk
OPENCV_CAMERA_MODULES := off
include $(OPENCV_PACKAGE_DIR)/native/jni/OpenCV.mk

LOCAL_MODULE    := run_detection
LOCAL_SHARED_LIBRARIES := libtess
LOCAL_SRC_FILES := text_detect.cpp android.cpp
LOCAL_LDLIBS    += -landroid -llog -ldl

include $(BUILD_SHARED_LIBRARY)

And this is the output:

[armeabi-v7a] Prebuilt       : liblept.so <= src/main/jni/../libs/armeabi-v7a/
[armeabi-v7a] Install        : liblept.so => src/main/jniLibs/armeabi-v7a/liblept.so
[armeabi-v7a] Prebuilt       : libtess.so <= src/main/jni/../libs/armeabi-v7a/
[armeabi-v7a] Install        : libtess.so => src/main/jniLibs/armeabi-v7a/libtess.so
[armeabi] Prebuilt       : liblept.so <= src/main/jni/../libs/armeabi/
[armeabi] Install        : liblept.so => src/main/jniLibs/armeabi/liblept.so
[armeabi] Prebuilt       : libtess.so <= src/main/jni/../libs/armeabi/
[armeabi] Install        : libtess.so => src/main/jniLibs/armeabi/libtess.so
[mips] Prebuilt       : liblept.so <= src/main/jni/../libs/mips/
[mips] Install        : liblept.so => src/main/jniLibs/mips/liblept.so
[mips] Prebuilt       : libtess.so <= src/main/jni/../libs/mips/
[mips] Install        : libtess.so => src/main/jniLibs/mips/libtess.so
[x86] Prebuilt       : liblept.so <= src/main/jni/../libs/x86/
[x86] Install        : liblept.so => src/main/jniLibs/x86/liblept.so
[x86] Prebuilt       : libtess.so <= src/main/jni/../libs/x86/
[x86] Install        : libtess.so => src/main/jniLibs/x86/libtess.so

As you see it installs everything from the first Android.mk perfectly, but it never runs textdetect/Android.mk

So, what I'm I doing wrong? How can I achieve this task that seems so simple? Is there an easier way?

EDIT:

After @ph0b response I went back to my first setup and added the same LOCAL_EXPORT_C_INCLUDES as the original Makefiles (with a couple of variations adapting it to my paths), and that solved it. It couldn't find platform.h because it didn't know where to look for it.

Now, after I did this change I had a different error No such file or directory #include "com_googlecode_tesseract_android/src/api/baseapi.h" and I thought this was because it didn't compile tesseract before run_detection that depends on it. Well that wasn't the problem, it still compiles run_detection before tesseract but that wasn't the issue, it was so much simpler and I feel so stupid for having spent so much time on this error. The problem was it didn't find com_googlecode_tesseract_android/src/api/baseapi.h because I didn't provide the path for that either, so I copied com_googlecode_tesseract_android and com_googlecode_leptonica_android from tess-two and added $(LOCAL_PATH) to LOCAL_EXPORT_C_INCLUDES. This is my final solution:

jni folder structure:

Android.mk
Application.mk
text_detect.cpp
android.cpp
text_detect.h
com_googlecode_leptonica_android
com_googlecode_tesseract_android

Android.mk

LOCAL_PATH := $(call my-dir)

#leptonica
LEPTONICA_LOCAL := $(LOCAL_PATH)/com_googlecode_leptonica_android
LEPTONICA_PATH := $(LEPTONICA_LOCAL)/src

include $(CLEAR_VARS)

LOCAL_MODULE := liblept
LOCAL_SRC_FILES := ../libs/$(TARGET_ARCH_ABI)/liblept.so
LOCAL_EXPORT_C_INCLUDES := \
  $(LEPTONICA_LOCAL) \
  $(LEPTONICA_PATH)/src

include $(PREBUILT_SHARED_LIBRARY)

#tesseract
TESSERACT_LOCAL := $(LOCAL_PATH)/com_googlecode_tesseract_android
TESSERACT_PATH := $(TESSERACT_LOCAL)/src

include $(CLEAR_VARS)

LOCAL_MODULE := libtess
LOCAL_SRC_FILES := ../libs/$(TARGET_ARCH_ABI)/libtess.so
LOCAL_EXPORT_C_INCLUDES := \
  $(LOCAL_PATH) \
  $(TESSERACT_PATH)/api \
  $(TESSERACT_PATH)/ccmain \
  $(TESSERACT_PATH)/ccstruct \
  $(TESSERACT_PATH)/ccutil \
  $(TESSERACT_PATH)/classify \
  $(TESSERACT_PATH)/cube \
  $(TESSERACT_PATH)/cutil \
  $(TESSERACT_PATH)/dict \
  $(TESSERACT_PATH)/opencl \
  $(TESSERACT_PATH)/neural_networks/runtime \
  $(TESSERACT_PATH)/textord \
  $(TESSERACT_PATH)/viewer \
  $(TESSERACT_PATH)/wordrec \
  $(LEPTONICA_PATH)/src \
  $(TESSERACT_LOCAL)
LOCAL_SHARED_LIBRARIES := liblept

include $(PREBUILT_SHARED_LIBRARY)

#opencv
include $(CLEAR_VARS)
OPENCV_PACKAGE_DIR:= /Users/danielsierraf/Documents/OpenCV-2.4.10-android-sdk/sdk
OPENCV_CAMERA_MODULES := off
include $(OPENCV_PACKAGE_DIR)/native/jni/OpenCV.mk

LOCAL_MODULE    := run_detection
LOCAL_SRC_FILES := text_detect.cpp android.cpp
LOCAL_LDLIBS    += -landroid -llog -ldl
LOCAL_SHARED_LIBRARIES += libtess liblept

include $(BUILD_SHARED_LIBRARY)

Solution

  • Your latest setup is failing in a weird way, ndk-build should at least try to compile your module. Maybe there is a bug in all-subdir-makefiles when there are ndk modules defined before it, and it doesn't find your module's Android.mk. You can try having only include $(call all-subdir-makefiles) inside your top level Android.mk.

    Anyway, I think you should go back to your first setup, with your module directly in the jni root folder. Then, your main issue is the proper declaration of includes paths. tess-two/jni doesn't contain any headers ? They're in tess-two/jni/com_googlecode_*_android/src/*. That means you need to list these in your module declarations, by giving all the absolute paths to LOCAL_EXPORT_C_INCLUDES variables (like from the original Makefiles: https://github.com/rmtheis/tess-two/blob/master/tess-two/jni/com_googlecode_tesseract_android/Android.mk#L33)

    You also need to add the dependency on liblept for libtess: LOCAL_SHARED_LIBRARIES := liblept inside libtess library declaration.

    If it still fails, there is also another possibility: instead of redefining libtess and liblept modules using the generated .so files, you can directly include tess-two/jni/Android.mk and use the same Application.mk than tess-two (copy `tess-two/jni/Application.mk). It will already properly define libtess and liblept modules.