0

System information

  • OpenCV 4.3 / 3.4
  • Linux Ubuntu 16.04
  • Android Studio (Gradle / Ninja / CMake / clang++)

Detailed description

I'm trying to use OpenCV on Android's NDK. I have two similar environments - one integrated with OpenCV 4.3 and the other with OpenCV 3.4. I created an Android C++ app. For the 4.3 integration I followed this tutorial. For the 3.4 integration I followed this tutorial. I have a very basic native-lib.cpp file (see below), which is trying to use cv::imread.

In my code I provide the last trial - which includes the OpenCVLoader.initAsync instance, but I also tried the OpenCVLoader.initDebug way and System.loadLibrary("opencv_java4"), but the error remains.

I tried to build for my SDK version or against libc++, as described in the following:

and noticed some other issues, which do not use exactly the same setup (for example, using ndk-build instead of cmake):

but failed to solve the issue.

When trying to run the app I get the following errors:

undefined reference to `cv::imread'
clang++: error: linker command failed with exit code 1 (use -v to see invocation)
ninja: build stopped: subcommand failed.

Isn't undefined reference a linker issue? Did I forget a compiler flag or something?

Steps to reproduce

Follow one of the tutorials (4.3 tutorial or 3.4 tutorial) to integrate OpenCV library into Android Studio.

Create the following simple native-lib.cpp:

#include <jni.h>
#include <string>
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>

extern "C" JNIEXPORT jstring JNICALL
Java_com_ocv_MainActivity_ocvLoadImage(
        JNIEnv *env,
        jobject thiz) {
    using namespace cv;
    using namespace std;
    Mat image;
    string imageName = "/Pictures/images/image-001.jpg";
    image = imread(imageName, IMREAD_COLOR);
    std::string returnString = "OpenCV load image: ";
    if (! image.empty()){
        returnString.append(imageName);
    }
    return env -> NewStringUTF(returnString.c_str());
}

and call it from this simple MainActivity.java:

package com.ocv;

import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
import android.util.Log;
import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.LoaderCallbackInterface;
import org.opencv.android.OpenCVLoader;
import org.opencv.core.Mat;

public class MainActivity extends AppCompatActivity {

    static {
        System.loadLibrary("native-lib");
        System.loadLibrary("opencv_java4");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
        @Override
        public void onManagerConnected(int status) {
            if (status == LoaderCallbackInterface.SUCCESS) {
                TextView textView = findViewById(R.id.sample_text);
                String displayString =
                        textView.getText() +
                                "\n" + "OpenCV loaded successfully via initAsync" +
                                "\n" + ocvLoadImage();
                textView.setText(displayString);
            } else {
                super.onManagerConnected(status);
            }
        }
    };

    @Override
    public void onResume()
    {
        super.onResume();
        OpenCVLoader.initAsync(
                OpenCVLoader.OPENCV_VERSION_3_4_0,
                this,
                mLoaderCallback);
    }
    public native String ocvLoadImage(String imagePath);
}

NOTES:

  • When calling OpenCVLoader.initAsync, both the 4.3 and the 3.4 version use the OPENCV_VERSION_3_4_0 flag, since OPENCV_VERSION on 4.3 results in an error. I also tried the OpenCVLoader.initDebug and it produces the same error.
  • When commenting out the image = imread line in native-lib.cpp, the app runs OK, and returns the string (all cases).

the app's build.gradle:

externalNativeBuild {
            cmake {
                        cppFlags "-frtti -fexceptions"
                        abiFilters 'arm64-v8a'
                        arguments "-DOpenCV_DIR=" + opencvsdk + "/sdk/native/jni"
            }
}
...
packagingOptions {
        pickFirst 'lib/arm64-v8a/libopencv_java4.so'
    }

CMakeLists.txt:

cmake_minimum_required(VERSION 3.4.1)
include_directories(${OpenCV_DIR}/jni/include)
find_package(OpenCV 4.3
        REQUIRED
        java)
add_library(
             native-lib
             SHARED
             native-lib.cpp )
find_library(
              log-lib
              log )
target_link_libraries( # Specifies the target library.
        native-lib
        ${OpenCV_LIBRARIES}
        ${log-lib} )

Error

ERROR:

undefined reference to "cv::imread"

BUILD:

Build command failed.
Error while executing process /path/to/Sdk/cmake/3.10.2.4988404/bin/ninja with arguments {-C /path/to/app/.cxx/cmake/debug/arm64-v8a native-lib}
ninja: Entering directory `/path/to/app/.cxx/cmake/debug/arm64-v8a'
[1/2] Building CXX object CMakeFiles/native-lib.dir/native-lib.cpp.o
[2/2] Linking CXX shared library /path/to/app/build/intermediates/cmake/debug/obj/arm64-v8a/libnative-lib.so
FAILED: /path/to/app/build/intermediates/cmake/debug/obj/arm64-v8a/libnative-lib.so 
: && /path/to/Sdk/ndk/21.1.6352462/toolchains/llvm/prebuilt/linux-x86_64/bin/clang++ --target=aarch64-none-linux-android29 --gcc-toolchain=/path/to/Sdk/ndk/21.1.6352462/toolchains/llvm/prebuilt/linux-x86_64 --sysroot=/path/to/Sdk/ndk/21.1.6352462/toolchains/llvm/prebuilt/linux-x86_64/sysroot -fPIC -g -DANDROID -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -D_FORTIFY_SOURCE=2 -Wformat -Werror=format-security  -frtti -fexceptions -O0 -fno-limit-debug-info  -Wl,--exclude-libs,libgcc.a -Wl,--exclude-libs,libgcc_real.a -Wl,--exclude-libs,libatomic.a -static-libstdc++ -Wl,--build-id -Wl,--fatal-warnings -Wl,--no-undefined -Qunused-arguments -shared -Wl,-soname,libnative-lib.so -o /path/to/app/build/intermediates/cmake/debug/obj/arm64-v8a/libnative-lib.so CMakeFiles/native-lib.dir/native-lib.cpp.o  /path/to/OpenCV-android-sdk/sdk/native/libs/arm64-v8a/libopencv_java4.so /path/to/Sdk/ndk/21.1.6352462/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/29/liblog.so -ljnigraphics -llog -ldl -lz -latomic -lm && :

MORE

Tried How can I integrate OpenCV 4.0 into a pure C++ Android NDK project? :

CMakeLists.txt:

cmake_minimum_required(VERSION 3.4.1)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
set(CMAKE_ANDROID_STL_TYPE c++_static)
set( OpenCV_DIR "/path/to/opencv-4.3.0-android-sdk/OpenCV-android-sdk/sdk/native/jni" )

find_package(OpenCV
        REQUIRED
        java)

add_library(native-lib
             SHARED
             native-lib.cpp )

get_target_property(__src opencv_java IMPORTED_LOCATION_RELEASE )
add_custom_command(TARGET native-lib POST_BUILD COMMAND
        ${CMAKE_COMMAND} -E copy ${__src} ${CMAKE_LIBRARY_OUTPUT_DIRECTORY})

include_directories(${OpenCV_INCLUDE_DIRS})

find_library( log-lib
              log )

target_link_libraries(
        native-lib
        opencv_java
        ${log-lib} )

but still get the same error.

  • 1
    Can you provide the complete CMake output, and it would be helpful to see what is actually being linked, if you can add the verbose linker output as well. – Kevin Jun 10 '20 at 12:43
  • @squareskittles thanks for the comment - I added the build line from Gradle, including the CMake output. Is this what you meant? – orangesomethingorange Jun 14 '20 at 15:24
  • Yes, undefined reference indicates that something has not been linked, and in this case, you are *missing* linkage to the OpenCV `imgcodecs` library (see this [response](https://stackoverflow.com/questions/34497099/opencv-undefined-reference-to-imread)). You could try adding these missing components to your `find_package` call: `find_package(OpenCV COMPONENTS java core imgproc imgcodecs highgui REQUIRED)` – Kevin Jun 16 '20 at 12:15
  • @squareskittles thanks for the tip, it didn't change anything though... BTW I can include OpenCV components (like core / imgcodecs / etc) in native code, and if I search for the function declaration it opens the correct *.hpp files (for example: 'imgcodecs.hpp' file for 'imread' function), **but trying to build** the project results in the above error.... any idea what it means? – orangesomethingorange Jun 17 '20 at 13:08

0 Answers0