Why am I getting undefined reference to cv::imwrite?
I'm developing an app for android with react-native that uses opencv and the imread and imwrite functions. They are in the same header file(using opencv version 3.4.1), but I get an undefined reference when trying to use imwrite, NOT imread. Imread reads the image perfectly and I am able to do my image analysis, but can't save the post-processed image as I get this error. Any thoughts?
Here is the c++ code:
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
extern "C"
{
void JNICALL Java_com_app_ImageConvert_OpencvNativeClass_invertImage(JNIEnv *env, jobject instance,
jstring filePath, jstring invertedFilePath) {
// get file paths
const char *filePathStr = env->GetStringUTFChars(filePath, 0);
const char *invertedFilePathStr = env->GetStringUTFChars(invertedFilePath, 0);
// read photo with path
Mat image = imread( filePathStr , IMREAD_COLOR);
// image analysis code here
// save image
imwrite(invertedFilePathStr,image);
Java Code to get file paths:
File dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);
//make path of photo with gallery path
String imageName;
int index = imagePath.lastIndexOf("/");
imageName = imagePath.substring(index+1, imagePath.length()-4);
String filePath = dir.getAbsolutePath() + "/" + imageName + ".jpg";
//make path of inverted photo
String invertedFilePath = dir.getAbsolutePath() + "/" + imageName + "_inverted.jpg";
Here is CMakeLists.txt
cmake_minimum_required(VERSION 3.4.1)
include_directories(/Users/USER/Downloads/opencv-3.4.1-android-sdk/OpenCV-android-sdk/sdk/native/jni/include)
add_library( lib_opencv SHARED IMPORTED )
set_target_properties(lib_opencv PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libopencv_java3.so)
add_library( # Sets the name of the library.
native-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
# Associated headers in the same location as their source
# file are automatically included.
src/main/cpp/native-lib.cpp )
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log )
target_link_libraries( # Specifies the target library.
native-lib
# OpenCV lib
lib_opencv
# Links the target library to the log library
# included in the NDK.
${log-lib} )
Here is the Error Message:
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':app:externalNativeBuildDebug'.
> Build command failed.
Error while executing process C:\Users\USER\AppData\Local\Android\Sdk\cmake\3.6.4111459\bin\cmake.exe with arguments {--build C:\Users\USER\Desktop\App\android\app\.externalNativeBuild\cmake\debug\armeabi-v7a --target native-lib}
[1/1] Linking CXX shared library ..\..\..\..\build\intermediates\cmake\debug\obj\armeabi-v7a\libnative-lib.so
FAILED: cmd.exe /C "cd . && C:\Users\USER\AppData\Local\Android\Sdk\ndk-bundle\toolchains\llvm\prebuilt\windows-x86_64\bin\clang++.exe --target=armv7-none-linux-androideabi --gcc-toolchain=C:/Users/USER/AppData/Local/Android/Sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/windows-x86_64 --sysroot=C:/Users/USER/AppData/Local/Android/Sdk/ndk-bundle/sysroot -fPIC -isystem C:/Users/USER/AppData/Local/Android/Sdk/ndk-bundle/sysroot/usr/include/arm-linux-androideabi -D__ANDROID_API__=16 -g -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -mthumb -Wa,--noexecstack -Wformat -Werror=format-security -std=c++11 -frtti -fexceptions -O0 -fno-limit-debug-info -Wl,--exclude-libs,libgcc.a -Wl,--exclude-libs,libatomic.a -nostdlib++ --sysroot C:/Users/USER/AppData/Local/Android/Sdk/ndk-bundle/platforms/android-16/arch-arm -Wl,--build-id -Wl,--warn-shared-textrel -Wl,--fatal-warnings -Wl,--fix-cortex-a8 -Wl,--exclude-libs,libunwind ...
show code, please. mk files, anything you deem useful.
Actually in your C++ code, you never really check if the imread actually succeeded in filling the Mat element (and thus read a valid image, before writing). Can you add a
if(image.empty()){ cerr << "Go bezerk >_<!"; return -1; }
right after the imread? If that fails, it means your string for reading the image is wrong.So part of the image analysis is a circle detection, and I have this in my image analysis:
if (circles.size() == 1){usleep(5000000);
And if I take of picture with a circle I get this 5 second pause.^^ that is entirely unrelated and irrelevant.
yea, good luck there, you're way off the trodden path.
can you add the exact error msg to your question, please ?
(imwrite() has an additional params arg, with a std::vector. your android c++ libs might have somethong slightly different here)
Your saying the fact that this is in react-native is irrelevant? Or is it the bit of code I've added? And I edited the question to include the exact error message.
no, the timeout code is irrelevant.
'cv::imwrite(cv::String const&, cv::_InputArray const&, std::__ndk1::vector<int, std::__ndk1::allocator<int> > const&)
look at the last arg.i can only guess, but it looks like your android libs were compiled against a different c++ std implementation as the react native code youre trying to compile now.
Hmm, I'm not certain how I would check/fix it if this is the issue. Also, the point of the timeout code was to answer @StevenPuttemans question that imread is indeed reading an image that isn't empty.
You may try to use an older version of NDK, e.g., 16b.