I am trying to use OpenCV library for my Android app (OpenCV 4.6.0). But the size of my app is really big after I added the library. I want to only include the part of the library that I use, which is imgproc
and core
(specifically Sobel edge detection). I have tried to edit the CMakeLists.txt (which is located on libcxx_helper) to this:
cmake_minimum_required(VERSION 3.6)
# dummy target to bring libc++_shared.so into packages
add_library(opencv_jni_shared STATIC dummy.cpp)
set(OpenCV_DIR D:/Project/AndroidStudioProject/SobelProject/sdk/native/jni)
find_package(OpenCV REQUIRED core imgproc)
add_executable(opencv_sobel dummy.cpp)
target_link_libraries(opencv_sobel core imgproc ${EXTERNAL_LIBS})
I expect there will be a libopencv_sobel.so
generated from the above CMakeLists.txt, but nothing is generated. So, I load the library with this:
init {
System.loadLibrary('opencv_java4')
}
Then I run the app. But the size of my app is still the same. I am unfamiliar with C++ and NDK.
Any help would be very appreciated.
EDIT:
I follow exactly the same step from the documentation @Rohit Bhati gave.
This is my Android.mk
include $(CLEAR_VARS)
OPENCV_INSTALL_MODULES:=on
include D:\Project\AndroidStudioProject\OpenCV-android-sdk\sdk\native\jni\OpenCV.mk
OPENCV_CAMERA_MODULES:=off
OPENCV_LIB_TYPE:=STATIC
and this is my Application.mk
APP_STL := c++_static # I changed it from gnustl_static because it is not supported anymore
APP_CPPFLAGS := -frtti -fexceptions
APP_ABI := arm64-v8a
APP_PLATFORM := android-21
both located at {myProject}/app/jni
then I ran the ndk-build
. After it completes, a libopencv_java4.so
file is generated inside the libs/armv64-v8
folder, but the size is still the same.
I look into the documentation but I didn't found how to specify what library I want to include. Also, what is the purpose of this code
OPENCV_CAMERA_MODULES:=off
because it doesn't reduce the .so
generated file size
EDIT 2
I followed the step from the related link by @Rohit Bhati with a slight different because the steps seems old.
/d/Project/AndroidStudioProject/OpenCV-android-sdk/sdk/native/staticlibs/arm64-v8a
$ D:/Android/Sdk/ndk/25.0.8775105/toolchains/llvm/prebuilt/windows-x86_64/bin/aarch64-linux-android21-clang++ -shared -o libopencv_java4.so --sysroot=D:/Android/Sdk/ndk/25.0.8775105/toolchains/llvm/prebuilt/windows-x86_64/sysroot -Wl,--whole-archive libopencv_core.a libopencv_imgproc.a -Wl,--no-whole-archive
$ D:/Android/Sdk/ndk/25.0.8775105/toolchains/llvm/prebuilt/windows-x86_64/bin/llvm-strip libopencv_java4.so
A new libopencv_java4.so
file then generated with smaller size. Then, I copy it to opencv-sdk/native/libs/armv64-v8a
replacing the old file (which is bigger one). But, I get this error
java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "_ZN3tbb4task13note_affinityEt" referenced by "/data/app/id.indevelopment.edgepaint-pG-fG4NFi7Mj7szExjH9ww==/lib/arm64/libopencv_java4.so"...
at java.lang.Runtime.loadLibrary0(Runtime.java:1071)
at java.lang.Runtime.loadLibrary0(Runtime.java:1007)
at java.lang.System.loadLibrary(System.java:1667)
at id.indevelopment.edgepaint.detector.EdgeDetection.<init>(EdgeDetection.kt:17)
at id.indevelopment.edgepaint.di.AppModuleKt$detectorModule$1$1.invoke(AppModule.kt:16)
at id.indevelopment.edgepaint.di.AppModuleKt$detectorModule$1$1.invoke(AppModule.kt:16)
at org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:54)
at org.koin.core.instance.FactoryInstanceFactory.get(FactoryInstanceFactory.kt:38)
at org.koin.core.registry.InstanceRegistry.resolveInstance$koin_core(InstanceRegistry.kt:111)
at org.koin.core.scope.Scope.resolveValue(Scope.kt:255)
at org.koin.core.scope.Scope.resolveInstance(Scope.kt:242)
at org.koin.core.scope.Scope.get(Scope.kt:205)
at id.indevelopment.edgepaint.di.AppModuleKt$viewModelModule$1$1.invoke(AppModule.kt:22)
at id.indevelopment.edgepaint.di.AppModuleKt$viewModelModule$1$1.invoke(AppModule.kt:11)
at org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:54)
at org.koin.core.instance.FactoryInstanceFactory.get(FactoryInstanceFactory.kt:38)
at org.koin.core.registry.InstanceRegistry.resolveInstance$koin_core(InstanceRegistry.kt:111)
at org.koin.core.scope.Scope.resolveValue(Scope.kt:255)
at org.koin.core.scope.Scope.resolveInstance(Scope.kt:242)
at org.koin.core.scope.Scope.get(Scope.kt:205)
at org.koin.androidx.viewmodel.factory.DefaultViewModelFactory.create(DefaultViewModelFactory.kt:13)
at androidx.lifecycle.ViewModelProvider$Factory.create(ViewModelProvider.kt:83)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.kt:187)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.kt:153)
at androidx.lifecycle.ViewModelLazy.getValue(ViewModelLazy.kt:53)
at androidx.lifecycle.ViewModelLazy.getValue(ViewModelLazy.kt:35)
at id.indevelopment.edgepaint.ui.main.MainActivity.getViewModel(MainActivity.kt:77)
at id.indevelopment.edgepaint.ui.main.MainActivity.setUpViewModel(MainActivity.kt:152)
at id.indevelopment.edgepaint.ui.main.MainActivity.onCreate(MainActivity.kt:112)
at android.app.Activity.performCreate(Activity.java:7893)
at android.app.Activity.performCreate(Activity.java:7880)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1306)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3310)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3484)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2068)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:224)
at android.app.ActivityThread.main(ActivityThread.java:7551)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:539)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:995)