I am trying to write a C++ file in Android Studio and I would like to use OpenCV in my project.
However, when I try to use the following includes, I get an error saying Cannot Find 'opencv2'.
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/features2d.hpp>
To set up OpenCV in Android, you have to take the following steps, found here, to use the Java part of OpenCV in Android Studio.
To the best of my knowledge to use the C++ part of OpenCV in Android Studio, you have to add Android.mk and Application.mk to the folder containing your native code.
My Android.mk file looks like the following.
LOCAL_PATH := $(call my-dir)
CVROOT := C:/Users/Dan/Documents/Repos/Android-Studio/Assets/opencv-3.4.1-android-sdk/OpenCV-android-sdk/sdk/native/jni
include $(CLEAR_VARS)
OPENCV_CAMERA_MODULES:=on
OPENCV_INSTALL_MODULES:=on
OPENCV_LIB_TYPE:=SHARED
include $(CVROOT)/OpenCV.mk
LOCAL_MODULE := app
LOCAL_SRC_FILES := native-lib.cpp
LOCAL_LDLIBS += -llog -ldl
include $(BUILD_SHARED_LIBRARY)
My Application.mk file looks like the following.
APP_STL := gnustl_static
APP_CPPFLAGS := -frtti -fexceptions
APP_ABI := armeabi-v7a
APP_PLATFORM := android-27
Am I doing something wrong to set my project up to use the C++ part of OpenCV on Android?
Additional Information for if it makes a difference
My project outline looks like this.
My gradles look like the following
app module
apply plugin: 'com.android.application'
android {
compileSdkVersion 27
defaultConfig {
applicationId "com.test.test.esra"
minSdkVersion 24
targetSdkVersion 27
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
cppFlags "-frtti -fexceptions"
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support:appcompat-v7:27.1.0'
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
// Room - Managing local databases
implementation 'android.arch.persistence.room:runtime:1.0.0'
annotationProcessor "android.arch.persistence.room:compiler:1.0.0"
//Jetbrains Annotations
implementation 'org.jetbrains:annotations-java5:15.0'
implementation project(':openCVLibrary341')
}
openCVLibrary341 module
apply plugin: 'com.android.library'
android {
compileSdkVersion 27
defaultConfig {
minSdkVersion 24
targetSdkVersion 27
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
}
}
project build.gradle
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
For anyone else who arrives here with the same issue, the problem is fairly easy to fix.
You no longer need the .mk files so they can be deleted.
If you are starting a project from scratch, make sure you have Android NDK and CMake installed as well as enabling them for your project.
After following the initial steps posted in this answer to set up the Java part of OpenCV on Android. You will need to change your app module's build gradle to reflect the snippet below.
defaultConfig {
...
externalNativeBuild {
cmake {
cppFlags "-frtti -fexceptions"
abiFilters 'x86', 'x86_64', 'armeabi', 'armeabi-v7a', 'arm64-v8a', 'mips', 'mips64'
}
}
}
sourceSets {
main {
jniLibs.srcDirs = ['src/main/jniLibs']
}
}
Then you want to edit the file CMakeLists.txt. In this file you want to include the following code underneath the cmake_minimum_required(VERSION X.X.X) line.
Also, you will need to add lib_opencv to the target_link_libraries near the bottom of CMakeLists.txt. This will help prevent undefined reference errors.
include_directories(your-path-to/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)
...
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} )
Make sure to replace your-path-to with your actual path to OpenCV for Android.
Finally, clean your project and refresh your linked C++ projects. This will remove the error.
I got this information from this really nice GitHub page. Credits to leadrien
Clarification on You no longer need the .mk files. This is true for Android Studio 3. I have not tested this on older versions of Android Studio or Eclipse, so you might need .mk files for those IDEs.
Related
I'm trying to build Tensorflow lite with C++ natively on Android device. I've built a .So file of tensorflow for every architecture and placed into the jniLibs folder. This is my Cmake file:
set(pathToProject /ih/user/project/NativeTfLite/app)
set(libs ${pathToProject}/src/main/jniLibs)
add_library(libtensorflowLite SHARED IMPORTED
)
set_target_properties(libtensorflowLite PROPERTIES IMPORTED_LOCATION
${libs}/${ANDROID_ABI}/libtensorflowLite.so)
find_library(
log-lib
log )
add_library(
native-lib
SHARED
native-lib.cpp)
target_include_directories(native-lib PRIVATE
${lib}/include)
target_link_libraries( # Specifies the target library.
native-lib. #Problem is here when linking native-lib with libtensorflowlite
libtensorflowLite
${log-lib} )
During compile time these files are found. However in target_link_libraries line, the linking of the 2 libraries libtensorflowlite and native-lib there is a runtime crash with the following error:
java.lang.UnsatisfiedLinkError: dlopen failed: library "/Users/ih/project/cameraFrames/NativeTfLite/app/src/main/jniLibs/arm64-v8a/libtensorflowLite.so" not found
Additionally the .SO files are not linked to the APK.
Here is my build.gradle file:
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 29
buildToolsVersion "29.0.3"
defaultConfig {
applicationId "com.proj.nativetflite"
minSdkVersion 24
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
sourceSets {
main {
jniLibs.srcDir 'src/main/jniLibs'
jniLibs.srcDirs = ["src/main/jniLibs"]
}
}
externalNativeBuild {
cmake {
cppFlags "-std=c++11"
arguments '-DCMAKE_VERBOSE_MAKEFILE=ON'
}
}
ndk {
abiFilters "armeabi-v7a", "x86" , "arm64-v8a"
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
version "3.10.2"
}
}
}
dependencies {
implementation fileTree(dir: 'jniLibs', include: '**/*.so')
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.core:core-ktx:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}
What is causing this?
Prior to AGP 4.0 you need to explicitly package prebuilt libraries with jniLibs: https://developer.android.com/studio/projects/gradle-external-native-builds#jniLibs. Note that the docs say you don't need to do this for anything declared by CMake, but I'm fairly certain the docs are wrong here (I've reached out to the doc owner to see if we need to fix that or not, since it is correct for 4.0).
This should be unnecessary in 4.0, but that hasn't reached stable yet.
Although I think Dan Albert's answer should be accepted, I'd like to add that I got the exact same error because I had not set the correct path to my tflite lib.
I kept my .so files in src/main/cpp/tflite/lib/${ANDROID_ABI}/, so in build.gradle I needed to add:
main {
jniLibs.srcDirs = ['src/main/cpp/tflite/lib']
}
also, it could be worth checking out this answer (also from Dan) regarding making sure the SONAME of the .so is correct.
I am trying to compile an android project using Android.mk and need to include the following libraries: native-audio-jni android log OpenSLES.
A similar project (https://github.com/googlesamples/android-ndk/tree/master/native-audio), which includes the same libraries but uses CMakeLists.txt instead of Android.mk has this line in the CMakeLists.txt:
target_link_libraries(native-audio-jni android log OpenSLES)
This sample project builds and runs fine.
Based on findings from my online research on the topic, I have tried including the following lines in my Android.mk file, which is in the jni folder:
LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog -lOpenSLES -lnative-audio-jni
LOCAL_LDLIBS += -landroid
ldLibs = ["android", "log", "native-audio-jni", "OpenSLES"]
LOCAL_SHARED_LIBRARIES += libandroid
LOCAL_LDLIBS := -llog
However, I still get errors like:
undefined reference to `AAssetManager_fromJava'
undefined reference to `AAssetManager_open'
undefined reference to `SL_IID_SEEK'
undefined reference to `SL_IID_MUTESOLO' ...
I also have the following includes in my .c file where the errors are generated:
// for native audio
#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>
// for native asset manager
#include <sys/types.h>
#include <android/asset_manager.h>
#include <android/asset_manager_jni.h>
#include <android/log.h>
So my question is: How to add these libraries to my Android.mk or in other words: What is the equivalent of target_link_libraries(native-audio-jni android log OpenSLES) in Android.mk? For a number of reasons I need to use Android.mk instead of CMakeLists.txt in my project.
Here also is my build.gradle if this is of any help:
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-android'
android {
compileSdkVersion 27
defaultConfig {
applicationId "com.google.ar.sceneform.samples.drawing"
// 24 is the minimum since ARCore only works with 24 and higher.
minSdkVersion 24
targetSdkVersion 27
versionCode 1
versionName "1.0"
ndk {
//ldLibs "android", "log", "native-audio-jni", "OpenSLES" // Not helping
/*
* Sceneform is available for the following ABIs: arm64-v8a, armv7a,
* x86_64 and x86. This sample app enables arm64-v8a to run on
* devices and x86 to run on the emulator. Your application should
* list the ABIs most appropriate to minimize APK size (arm64-v8a recommended).
*/
abiFilters 'arm64-v8a' ,'x86' // , 'armeabi-v7a'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
externalNativeBuild {
ndkBuild {
path '../jni/Android.mk'
}
}
lintOptions {
abortOnError false
}
}
dependencies {
//implementation fileTree(dir: 'libs', include: ['*.jar']) // NOT helping
implementation 'com.google.ar.sceneform.ux:sceneform-ux:1.7.0'
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support:design:27.1.1'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation files('Libs/YouTubeAndroidPlayerApi.jar')
implementation 'com.github.barteksc:android-pdf-viewer:2.0.3'
implementation 'com.xw.repo:bubbleseekbar:3.19-lite'
}
repositories {
mavenCentral()
}
apply plugin: 'com.google.ar.sceneform.plugin'
sceneform.asset('sampledata/models/andy.obj',
'default',
'sampledata/models/andy.sfa',
'src/main/res/raw/andy')
And my Android.mk file:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
include $(CLEAR_VARS)
LOCAL_MODULE := aubio
LOCAL_SRC_FILES := $(TARGET_ARCH_ABI)/libaubio.so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := pitch
LOCAL_SRC_FILES := pitch.c
LOCAL_SHARED_LIBRARIES := aubio
include $(BUILD_SHARED_LIBRARY)
LOCAL_LDLIBS := -llog -lOpenSLES -lnative-audio-jni -landroid
An this is a screenshot of the built error:
enter image description here
Your Android.mk got some unnecessary definitions that ruin happen to hide he correct one:
LOCAL_LDLIBS := -llog -lOpenSLES -lnative-audio-jni -landroid
instead of all the lines that you posted. NDK knows where to find these libraries, therefore -L$(SYSROOT)/… is not necessary, but only can hurt. The other lines probably come from frustration.
I'm using NDK to use C++ native code in OpenCV through Android studio.
Every thing is alright except when I'm running this project to an android device I have the following error
Warning:Native C/C++ source code is found, but it seems that NDK option is not configured. Note that if you have an Android.mk, it is not used for compilation. The recommended workaround is to remove the default jni source code directory by adding:
android {
sourceSets {
main {
jni.srcDirs = []
}
}
}
and also
to build.gradle, manually compile the code with ndk-build, and then place the resulting shared object in src/main/jniLibs.
C:\Users\MALIK\Desktop\ImageJ\app\src\main\jni\com_example_malik_imagej_DetectionBasedTracker.cpp
Error:(2, 10) 'opencv2/opencv.hpp' file not found 1 error generated.
and when I do the workaround and make jni.srcDir empty , I got error that "cannot resolve corresponding JNI function "
so the native code won't run and the app crashes , what should I do in this case?
this is my gradle :
apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
defaultConfig {
applicationId "com.example.malik.haar"
minSdkVersion 16
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
task ndkBuild(type: Exec, description: 'Compile JNI source via NDK') {
commandLine "C:/Android/sdk/ndk-bundle/ndk-build.cmd",
'NDK_PROJECT_PATH=build/intermediates/ndk',
'NDK_LIBS_OUT=src/main/jniLibs',
'APP_BUILD_SCRIPT=src/main/jni/Android.mk',
'NDK_APPLICATION_MK=src/main/jni/Application.mk'
}
tasks.withType(JavaCompile) {
compileTask -> compileTask.dependsOn ndkBuild
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
sourceSets { main { jni.srcDirs = [] } }
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
compile 'com.android.support:appcompat-v7:23.1.1'
androidTestCompile files('libs/junit-4.12.jar')
compile project(':openCVLibrary320')
}
and this is my Android.mk file :
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
OPENCVROOT:=C:\OpenCV-android-sdk
OPENCV_INSTALL_MODULES:=on
OPENCV_LIB_TYPE:=SHARED
include $(OPENCVROOT)/sdk/native/jni/OpenCV.mk
LOCAL_SRC_FILES := com_example_malik_imagej_DetectionBasedTracker.cpp
LOCAL_C_INCLUDES += $(LOCAL_PATH)
LOCAL_LDLIBS += -llog -ldl
LOCAL_MODULE := detection_based_tracker
include $(BUILD_SHARED_LIBRARY)
and this is my Header file of native code :
thanks.
So I want to modify one of the files in the OpenCV build for Android and I followed the instructions on their site to download the build and I was able to make it successfully. I modified one of the files (calibinit.cpp) and made it again and copied the files in the
opencv/platforms/build_android_arm/lib/
folder into the jniLibs folder of my AndroidStudio Project.
However, the changes I made are definitely not working. I already had a previous OpenCV library linked to my project, so I'm pretty sure it's still using the old code. How do I use the new build with my AndroidStudio Project?
Can you provide more details about how u use jni in Android Studio Project?
Did u try to clean and rebuild?
Do you have your own custom Android.mk? cause Android Studio will generate its own Android.mk, which can lead to unexpected result as u thought.
delete jniLibs folder and every so file, you don't need them.
define NDK path in local.properties file:
sdk.dir=D:\Android\SDK
ndk.dir=D:\Android\NDK
create a folder(i named it jni) and put Android.mk and Application.mk in it (and an empty dummy.c file for preventing future buggy errors)
as Roy said, Android Studio generates it's own Android.mk, we have our own Android.mk file and Android Studio must use it.jni.srcDirs = []prevents that generation!
Extract openCV sources somewhere, i put them here: D:\Android\Libs\OpenCV
here is my files, modify and use them
build.gradle:
apply plugin: 'com.android.application'
android {
compileSdkVersion 22
buildToolsVersion "22.0.1"
defaultConfig {
applicationId "your.package"
minSdkVersion 11
targetSdkVersion 22
versionCode 1
versionName "1.0"
}
sourceSets {
main {
jni.srcDirs = [] /*disables automatic ndk-build call */
}
}
task ndkBuild(type: Exec) {
commandLine file('D:\\Android\\NDK\\ndk-build.cmd').absoluteFile,
'NDK_PROJECT_PATH='+file('src\\main\\jni').absolutePath,
'APP_BUILD_SCRIPT='+file('src\\main\\jni\\Android.mk').absolutePath,
'NDK_APPLICATION_MK='+file('src\\main\\jni\\Application.mk').absolutePath,
'NDK_LIBS_OUT='+file('src\\main\\jniLibs').absolutePath
}
tasks.withType(JavaCompile) {
compileTask -> compileTask.dependsOn ndkBuild
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:22.1.1'
compile project(':openCVLibrary300rc1')
}
Application.mk:
APP_STL := gnustl_static
APP_CPPFLAGS := -frtti -fexceptions
APP_ABI := armeabi-v7a x86
APP_PLATFORM := android-8
Android.mk:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
#opencv
OPENCVROOT:= D:/Android/Libs/OpenCV
OPENCV_CAMERA_MODULES:=on
OPENCV_INSTALL_MODULES:=on
OPENCV_LIB_TYPE:=SHARED
include ${OPENCVROOT}/sdk/native/jni/OpenCV.mk
//I have a local source file, you can remove it
LOCAL_SRC_FILES := DetectionBasedTracker_jni.cpp
LOCAL_C_INCLUDES += $(LOCAL_PATH)
LOCAL_LDLIBS += -llog
LOCAL_MODULE := detection_based_tracker
include $(BUILD_SHARED_LIBRARY)
To run some Native code you can execute ndk-build command but I am confused if the Eclipse or Android Studio IDEs execute this command automatically on the Compile-time or how ndk-build command is related to the mentioned IDEs when I compile my code by eclipse or droid studio?
For eclipse, there are already too many online sources related to it, so I will talk about Android Studio here.
If you don't have your onw native files (C++,C) in your project, just put the .a or .so native libraries in the src/main/jniLibs folders and you don't have to modify anything in the gradle file. The system will do everything for you automatically.
If you have your own native files and have put them in the src/main/jni folder, then you have to create your own makefiles and put them in the jni folder as well. You also have to modify the gradle file in your app module.
Here is what I did for a face detection sample of opencv, and I got the original code from this wonderful post(Here), which was actually modified from another one's method for simpler execution. The philosophy is rather simple: compile the native source codes and put the generated .so/.a library into the jniLibs folder:
My project structure:
Project Structure
My makefiles (make sure you have the original sdk of the library for reference in the makefile):
Android.mk:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
OPENCV_CAMERA_MODULES:=on
OPENCV_INSTALL_MODULES:=on
OPENCV_LIB_TYPE:=SHARED
include /home/ng/Desktop/OpenCV-android-sdk/sdk/native/jni/OpenCV.mk
LOCAL_SRC_FILES := DetectionBasedTracker_jni.cpp
LOCAL_C_INCLUDES += $(LOCAL_PATH)
LOCAL_LDLIBS += -llog -ldl
LOCAL_MODULE := detection_based_tracker
include $(BUILD_SHARED_LIBRARY)
Application.mk:
APP_STL := gnustl_static
APP_CPPFLAGS := -frtti -fexceptions
APP_ABI := armeabi-v7a armeabi
APP_PLATFORM := android-19
My gradle.build file in the app module:
apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
defaultConfig {
applicationId "org.opencv.samples.facedetect"
minSdkVersion 14
targetSdkVersion 19
versionCode 1
versionName "1.0"
}
sourceSets.main.jni.srcDirs = []
task ndkBuild(type: Exec, description: 'Compile JNI source via NDK') {
// ndkDir = project.plugins.findPlugin('com.android.application').getNdkFolder()
commandLine "$ndkDir/ndk-build",
'NDK_PROJECT_PATH=build/intermediates/ndk',
'NDK_LIBS_OUT=src/main/jniLibs',
'APP_BUILD_SCRIPT=src/main/jni/Android.mk',
'NDK_APPLICATION_MK=src/main/jni/Application.mk'
}
tasks.withType(JavaCompile) {
compileTask -> compileTask.dependsOn ndkBuild
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.1.0'
compile project(':openCVLibrary300')
}
You don't actually have to change other gradle files for compiling the native part of the project.
You could also compile the native sources codes by command line and put the .so files back to the jniLibs folder. This also works.
I hope this could help in your problem.
If you want you could compile it using Terminal commands or else you could configure both the IDEs to do automatically
Today Android-Studio (Canary) Preview 1.3 RC1 got released with jni/ndk support out of the box. No need to call commandline tools anymore.
https://sites.google.com/a/android.com/tools/download/studio/canary/latest
Release Notes:
https://sites.google.com/a/android.com/tools/recent/androidstudiowithandroidndkpreviewsupportavailable