android - Android 与 OpenCV 3.4.0 和 NDK 的链接错误

标签 android c++ opencv gradle android-ndk

我正在尝试将使用 OpenCV 用 C++ 编写的现有计算机视觉代码移植到 Android NDK。我按照此处提供的信息成功导入了适用于 Java 和 NDK 的 OpenCV 库版本 3.4.0(使用官方预构建的 Android 包):Satck Overflow Answer - CMake configuration of OpenCV on Android .

我能够使用 Java 和 C++ 中的 OpenCV 功能编译和运行一些代码。但是,我遇到了 2 个与某些 OpenCV 函数相关的“ undefined reference ”链接错误:持久性 JSON 阅读器和特征 2D 描述符匹配器。

这是我收到的错误消息:

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.

以下是编译器无法链接的代码 fragment :

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

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

我已经清楚地确定了导致链接器错误的行,如上面的代码示例中所注释的那样。如果我将它们注释掉,编译会通过并且程序运行良好(当然没有我试图在 NDK 中实现的功能)。

我的猜测是我调用的 OpenCV 函数在预构建库中丢失或者与我用于 NDK 开发的编译器不兼容。我已经尝试更改 OpenCV 版本(3.3.0 和 3.4.0)。

有谁知道是什么原因导致的,我该如何解决?这是 OpenCV 中的已知错误,还是我的配置不受支持或只是错误?

我使用的是装有 Android Studio 3.1.2、NDK r17、构建工具 27.0.3 和 OpenCV 3.4.0 预构建 android 包的 Windows 10 计算机(我自己没有从源代码编译它)。下面是 CMake 和 build.gradle 文件:

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

渐变:

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')
}

最佳答案

最近,NDK 切换到 libc++ 作为默认 STL,但 OpenCV 是使用 gnuSTL 构建的。

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

您的图书馆会解决这个问题。

或者,您可以 rebuild OpenCV with c++_shared .

更新:好消息!你can只需下载 OpenCV 4.0.1,它就能与 NDK r.18+ 顺畅地工作。

关于android - Android 与 OpenCV 3.4.0 和 NDK 的链接错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50677231/

相关文章:

android - 尝试添加下拉刷新时 Webview 崩溃

c++ - 继承自任意数量的模板模板类

java - 如何使用android opencv访问CV_HAAR_SCALE_IMAGE

python - 没有收到来自opencv的连续帧

c++ - 如何为 OpenCV 找到对象的正确 HSV 阈值?

android - 为什么在 Android sqlite 数据库上没有调用 onUpgrade()?

android - DexException:多个dex文件定义

java - 如何隐藏菜单栏但仍通过菜单按钮访问它

c++ - 将两个选项之间的参数传递给一个类

c++ - 为什么允许某些非常量表达式作为 constexpr 逗号运算符的操作数?