5

I am trying to port existing computer vision code, written in C++ using OpenCV, to Android NDK. I successfully imported the OpenCV library version 3.4.0 (using the official pre-built Android package) for both Java and NDK by following the information provided here: Satck Overflow Answer - CMake configuration of OpenCV on Android.

I am able to compile and run some code with OpenCV functionalities in Java and in C++. However, I am stuck with 2 "undefined reference" linking errors related to some OpenCV functions: persistence JSON reader and feature 2D descriptor matcher.

Here are the error messages I get:

Build command failed.
Error while executing process D:\Librairies\Android_SDK\cmake\3.6.4111459\bin\cmake.exe with arguments {--build D:\Dev\Android\PageDetector\app\.externalNativeBuild\cmake\debug\x86_64 --target page-recognition-lib}
[1/1] Linking CXX shared library ..\..\..\..\build\intermediates\cmake\debug\obj\x86_64\recognition-lib.so
FAILED: cmd.exe /C "cd . && D:\Librairies\Android_SDK\ndk-bundle\toolchains\llvm\prebuilt\windows-x86_64\bin\clang++.exe  --target=x86_64-none-linux-android --gcc-toolchain=D:/Librairies/Android_SDK/ndk-bundle/toolchains/x86_64-4.9/prebuilt/windows-x86_64 --sysroot=D:/Librairies/Android_SDK/ndk-bundle/sysroot -fPIC -isystem D:/Librairies/Android_SDK/ndk-bundle/sysroot/usr/include/x86_64-linux-android -D__ANDROID_API__=21 -g -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -Wa,--noexecstack -Wformat -Werror=format-security -std=c++11 -std=c++11 -frtti -fexceptions -std=gnu++11 -O0 -fno-limit-debug-info  -Wl,--exclude-libs,libgcc.a -Wl,--exclude-libs,libatomic.a -nostdlib++ --sysroot D:/Librairies/Android_SDK/ndk-bundle/platforms/android-21/arch-x86_64 -Wl,--build-id -Wl,--warn-shared-textrel -Wl,--fatal-warnings -LD:/Librairies/Android_SDK/ndk-bundle/sources/cxx-stl/llvm-libc++/libs/x86_64 -Wl,--no-undefined -Wl,-z,noexecstack -Qunused-arguments -Wl,-z,relro -Wl,-z,now -shared -Wl,-soname,libpage-recognition-lib.so -o ..\..\..\..\build\intermediates\cmake\debug\obj\x86_64\recognition-lib.so.so [...] -llog -llog ../../../../src/main/jniLibs/x86_64/libopencv_java3.so -latomic -lm "D:/Librairies/Android_SDK/ndk-bundle/sources/cxx-stl/llvm-libc++/libs/x86_64/libc++_static.a" "D:/Librairies/Android_SDK/ndk-bundle/sources/cxx-stl/llvm-libc++/libs/x86_64/libc++abi.a" && cd ."
D:/Librairies/OpenCV-android-sdk_340/sdk/native/jni/include\opencv2/core/persistence.hpp:1264: error: undefined reference to 'cv::read(cv::FileNode const&, std::__ndk1::vector<cv::KeyPoint, std::__ndk1::allocator<cv::KeyPoint> >&)'
D:\Dev\Android\PageDetector\app\src\main\cpp/PageMatcher.cpp:170: error: undefined reference to 'cv::DescriptorMatcher::radiusMatch(cv::_InputArray const&, cv::_InputArray const&, std::__ndk1::vector<std::__ndk1::vector<cv::DMatch, std::__ndk1::allocator<cv::DMatch> >, std::__ndk1::allocator<std::__ndk1::vector<cv::DMatch, std::__ndk1::allocator<cv::DMatch> > > >&, float, cv::_InputArray const&, bool) const'
clang++.exe: error: linker command failed with exit code 1 (use -v to see invocation)
ninja: build stopped: subcommand failed.

Below are the pieces of code that the compiler fails to link:

//code that reads data from a JSON file
this->JSONFeatureFilePath = JSONFeatureFilePath;
cv::FileStorage reader(JSONFeatureFilePath, cv::FileStorage::READ);

this->bookTitle = (string) reader["book_title"];
this->pageNumber = (int) reader["page_num"];

string descType = (string)reader["desc_type"];
replace(descType.begin(), descType.end(), '_', '.');
this->descriptorType = descType;

reader["img_size"] >> this->imageSize;

//this instruction causes the linker error
reader["keypoints"] >> this->keyPoints;

reader["descriptors"] >> this->keyPointDescriptors;
reader["fsum2d"] >> this->fsum2DFeatureSummary;

reader.release();

and

//code performing key point descriptors matching
cv::Ptr<cv::DescriptorMatcher> matcher = cv::DescriptorMatcher::create(cv::DescriptorMatcher::BRUTEFORCE_HAMMING);

vector<vector<cv::DMatch>> matchesTmp;

//instruction responsible for the link error
matcher->radiusMatch(this->sortedMatches.at(refSortedIndex).refImage->getDescriptors(),
    this->testImage->getDescriptors(), matchesTmp, matchThreshold);

I have clearly identified the lines that cause the linker errors, as commented in the code samples above. If I comment them out, the compilation goes through and the program runs fine (of course without the functionalities I am trying to implement in the NDK).

My guess is that the OpenCV functions I call are missing in the pre-built library or are incompatible with the compiler I am using for NDK development. I have already tried changing OpenCV version (3.3.0 and 3.4.0).

Does anyone know what can cause this and how I could fix it? Is it a known bug in OpenCV or is it my configuration that is not supported or just wrong?

I am using a Windows 10 computer with Android Studio 3.1.2, NDK r17, build tools 27.0.3 and OpenCV 3.4.0 pre-built android package (I did not compile it from source myself). Below are the CMake and build.gradle files:

CMake:

cmake_minimum_required(VERSION 3.4.1)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
set(opencv_340_dir D:/Librairies/OpenCV-android-sdk_340/sdk/native/jni)
set(app_dir D:/Dev/Android/PageDetector/app)

# native recognition library API
add_library(recognition-lib
        SHARED
        src/main/cpp/recognition-lib.h
        src/main/cpp/recognition-lib.cpp
        # + my classes' h and cpp files
        )

# OpenCV lib linking and includes
include_directories(${opencv_340_dir}/include)
add_library(opencv-lib SHARED IMPORTED)
set_target_properties(opencv-lib PROPERTIES IMPORTED_LOCATION ${app_dir}/src/main/jniLibs/${ANDROID_ABI}/libopencv_java3.so)


find_library(log-lib log)

target_link_libraries(
                   recognition-lib
                   opencv-lib
                   ${log-lib}
                   )

target_link_libraries(recognition-lib ${log-lib})

gradle:

apply plugin: 'com.android.application'

android {
compileSdkVersion 27
defaultConfig {
    applicationId "com.companyname.detector"
    minSdkVersion 21
    targetSdkVersion 27
    versionCode 1
    versionName "1.0"
    testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    externalNativeBuild {
        cmake {
            cppFlags "-std=c++11 -frtti -fexceptions"
        }
    }
}
buildTypes {
    release {
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
}
externalNativeBuild {
    cmake {
        path "CMakeLists.txt"
    }
}
sourceSets {
    main {
        jniLibs.srcDirs = ['src/main/jniLibs/']
    }
}
}

dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support.constraint:constraint-layout:1.1.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation project(':openCVLibrary340')
}

1 Answer 1

9

Recently, NDK switched to libc++ as default STL, but OpenCV is built with gnustl.

externalNativeBuild {
  cmake {
    arguments "-DANDROID_STL=gnustl_shared"
  }
}

for your library will fix that.

Alternatively, you can rebuild OpenCV with c++_shared.

Update: Good news! You can simply download OpenCV 4.0.1 and it will work smoothly with NDK r.18+.

4
  • 1
    Finally a decent solution! It fixed my tons of undefined reference errors after upgrading to AS 3.1 + Gradle 4.4 + NDK 17.
    – John Hany
    Commented Jun 6, 2018 at 1:50
  • 1
    I suspected this could have to do with a stl incompatibility but did not know how to change it or which to use. This worked for me and is very helpful. Thanks. Commented Jun 6, 2018 at 8:01
  • Should I rebuild the opencv with the above mentioned gradle command or use it in my cpp Android Studio project?
    – ssk
    Commented Sep 22, 2018 at 6:29
  • @ssk you may try this approach to rebuild OpenCV, or download NDK r16.
    – Alex Cohn
    Commented Sep 22, 2018 at 10:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.