28

There are many questions and answers surrounding getting native opencv for android building properly. Some use gradle, others use external tools. These numerous, complicated, and often conflicting descriptions for native OpenCV builds might be simplified with a consistent starting point; when creating an Android Studio 2.2 Beta project, there is an way to include C++ support: Include C++ Supportenter image description here

This feature was added around June of 2016. See Android tools technical docs for more information.

Using Android Studio 2.2 or higher with the Android plugin for Gradle version 2.2.0 or higher, you can add C and C++ code to your app by compiling it into a native library that Gradle can package with your APK. Your Java code can then call functions in your native library through the Java Native Interface (JNI). If you want to learn more about using the JNI framework, read JNI tips for Android.

Checking the Include C++ Support generates an external build file called CMakeLists.txt.

# Sets the minimum version of CMake required to build the native
# library. You should either keep the default value or only pass a
# value of 3.4.0 or lower.

cmake_minimum_required(VERSION 3.4.1)

# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds it for you.
# Gradle automatically packages shared libraries with your APK.

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 )

# Searches for a specified prebuilt library and stores the path as a
# variable. Because system libraries are included in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.

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 )

# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in the
# build script, prebuilt third-party libraries, or system libraries.

target_link_libraries( # Specifies the target library.
                       native-lib

                       # Links the target library to the log library
                       # included in the NDK.
                       $\{log-lib} )

To recognize an Android project that uses native (C++) OpenCV code, the project will typically include a *.cpp file containing JNIEXPORT entries along with implementations that use #include <opencv...hpp> functionality. This, as opposed to importing the OpenCV module and copying the libs folder into jniLibs, which only allows calling OpenCV functionality from Java.

Is it possible to use this starting point to configure a OpenCV native 'hello world' app, proving the build is working?

ADDITIONAL INFORMATION 8/22
Since this puzzle is about CMake and less about OpenCV, I thought I'd give out a project starting point for those not interested in OpenCV. You could get the starting point project going reasonably quickly using the information in OpenCV in Android Studio.

Here is a youtube video that shows the creation of a new Android Studio project, importing OpenCV, configuring the native C++ build, resulting in the OpenCV "hello world" application that's equal to the one in gitHub.

ADDITIONAL INFORMATION 8/27
The version committed today, based on the answer from Bruno Alexandre Krinski does compile native OpenCV calls: https://github.com/sengsational/HelloCv . There is a separate problem concerning the "Installation Blocked" message, where, upon installation, Android warns the user "This app contains code that attempts to bypass Android's security protections." Since I am unsure that this is an issue with the build technique, I will not expand this question to include that issue (but if someone has input on that problem, please advise).

#Added 2 path definitions to support 20160825 additions
set(pathToProject C:/Users/Owner/AndroidStudioProjects/HelloCv)
set(pathToOpenCv C:/Users/Owner/OpenCV-3.1.0-android-sdk)

#Added by the IDE on project create
cmake_minimum_required(VERSION 3.4.1)

#Two sets suggested by Bruno Alexandre Krinski 20160825
set(CMAKE_VERBOSE_MAKEFILE on)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")

#Addition suggested by Bruno Alexandre Krinski 20160825
include_directories(${pathToOpenCv}/sdk/native/jni/include)

#Added by IDE on project create
add_library( native-lib SHARED src/main/cpp/native-lib.cpp )

#Addition suggested by Bruno Alexandre Krinski 20160825
add_library( lib_opencv SHARED IMPORTED )

#Addition suggested by Bruno Alexandre Krinski 20160825
set_target_properties(lib_opencv PROPERTIES IMPORTED_LOCATION ${pathToProject}/app/src/main/jniLibs/${ANDROID_ABI}/libopencv_java3.so)

#Added by IDE on project create
find_library( log-lib log )

#Added by IDE on project create, Removed and replace with additional parameter suggested by Bruno Alexandre Krinski 20160825
#target_link_libraries( native-lib $\{log-lib} )
target_link_libraries( native-lib $\{log-lib} lib_opencv)
Jeru Luke
  • 20,118
  • 13
  • 80
  • 87
Dale
  • 5,520
  • 4
  • 43
  • 79
  • What does your OpenCV **build.gradle** file look like? We need to know whether these are static or shared libs you are compiling. – IgorGanapolsky Sep 06 '16 at 20:19
  • It doesn't look like it's doing anything interesting: https://github.com/sengsational/HelloCv/blob/master/openCVLibrary310/build.gradle – Dale Sep 07 '16 at 01:40
  • There is more from the OpenCV team about doing native code on Android here: http://docs.opencv.org/doc/tutorials/introduction/android_binary_package/dev_with_OCV_on_Android.html#native-c – Dale Sep 07 '16 at 01:50
  • 1
    I see, so they are using Android.mk instead of Gradle-experimental NDK. So your approach with Cmake is good in this situation. – IgorGanapolsky Sep 07 '16 at 02:32
  • 1
    This question is really good. Some of the AndroidNDK/OpenCV tutorials that I've come across follow a cumbersome approach (see https://www.youtube.com/watch?v=Oq3oiCfSgbo), where you have to compile jni headers, etc., and the power of Android Studio's IntelliJ magic is lost. +1 for the question and +1 for the answer below. – ATutorMe Jan 18 '17 at 08:00
  • Installation blocked is not an issue. It happens for all the apps we side load (install from unofficial sources like manual installation) – FadedCoder Mar 10 '17 at 18:34
  • There is a proper way of integrating OpenCV as per OpenCV's CMake toolchain files. Please check my answer for more information: http://www.stackoverflow.com/a/43886764/2949966 – ahasbini May 11 '17 at 11:20

4 Answers4

26

It seems you already have imported the opencv module, now, open your CMakeList.txt and add the follow lines:

set(CMAKE_VERBOSE_MAKEFILE on)

add_library(lib_opencv SHARED IMPORTED)

set_target_properties(lib_opencv PROPERTIES IMPORTED_LOCATION
path-to-your-project/MyApplication/app/src/main/jniLibs/${ANDROID_ABI}/libopencv_java3.so)


include_directories(path-to-opencv-directory/OpenCV-android-sdk/sdk/native/jni/include)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")

and edit the:

target_link_libraries( # Specifies the target library.
                   native-lib
                   lib_opencv
                   # Links the target library to the log library
                   # included in the NDK.
                   $\{log-lib} )

to include your lib_opencv that you have created. To finish, you add the follow line:

abiFilters 'x86', 'x86_64', 'armeabi', 'armeabi-v7a', 'arm64-v8a', 'mips', 'mips64'

in your module app, like this:

externalNativeBuild {

    cmake {
        cppFlags "-std=c++11 -frtti -fexceptions"
        abiFilters 'x86', 'x86_64', 'armeabi', 'armeabi-v7a', 'arm64-v8a', 'mips', 'mips64'
    }
}

and below of buildTypes you add:

sourceSets {
    main {
        jniLibs.srcDirs = ['path to your application /MyApplication/app/src/main/jniLibs/']
    }
}

For more details, you can see this: https://github.com/googlesamples/android-ndk/tree/master/cmake/hello-libs

Alex Cohn
  • 56,089
  • 9
  • 113
  • 307
  • These suggested changes have been incorporated into the sample code on GitHub, and the project now compiles, albeit with a security warning. https://github.com/sengsational/HelloCv – Dale Aug 27 '16 at 15:51
  • 2
    Why did you write `$\{log-lib}` instead of `${log-lib}`? – Mateen Ulhaq Jul 23 '17 at 12:31
  • There is a missing " / " on "set_target_properties(lib_opencv PROPERTIES IMPORTED_LOCATION path to your project/MyApplication/app/src/main/jniLibs/${ANDROID_ABI}/libopencv_java3.so)" causing build erros. I can not edit the post! (won't change more than 6 chars) Thanks for the answer, saved me ! – Geraldo Neto Jul 24 '17 at 15:16
  • Any hints about how to use such thing in Unity for Android ? – Pierre Baret Nov 20 '17 at 23:00
  • I love you sir you just saved my life – Srinivas Nahak Nov 05 '18 at 12:03
8

With OpenCV 3.2 configuration could be actually quite short:

set(OpenCV_STATIC ON)
set(OpenCV_DIR ${OPENCV_HOME}/sdk/native/jni)
find_package (OpenCV REQUIRED)

target_link_libraries(native-lib ${OpenCV_LIBS})

That is it, 4 lines and no need to copy anything into your project. Just be sure that OPENCV_HOME points to the directory where OpenCV Android SDK is located.

One additional benefit of this approach - you can link with OpenCV statically, which would dramatically reduce the size of your app/library.

I use this approach in one of Github projects: https://github.com/Fotoapparat/FaceDetector

Dmitry Zaytsev
  • 23,650
  • 14
  • 92
  • 146
  • seems to be ok as my Android project linking in CMake another CMake subproject build correctly – Michał Ziobro Aug 12 '17 at 17:52
  • You mean only adding the above line to `CMakeLists.txt` ? – Hasani Jan 24 '18 at 06:25
  • I use OpenCV 3.4.0 and Android Strudio V2.3 – Hasani Jan 24 '18 at 06:27
  • @user8663682 you need to define this path in your environment variables. That is specific to the OS which you are using. – Dmitry Zaytsev Jan 24 '18 at 15:38
  • It worked for me but I am getting a message asking to install OpenCV Manager in runtime. May be its not related to CMakeList.txt – abggcv Jan 31 '18 at 04:59
  • 1
    @abggcv it is not. If you are building OpenCV yourself you do not need neither OpenCV Java SDK nor OpenCV Manager. – Dmitry Zaytsev Jan 31 '18 at 12:30
  • 1
    you are right I found that the android project I was working on was using some opencv android functions like camera bridge (something like that) and may be that is why OpenCV Manager was required. On another project I am simply using opencv to read image from file and its not asking for opencv manager anymore. So this works fine. One more thing I would like to add is that it didn't work for me until I added the path to include: `include_directories(${OPENCV_HOME}/sdk/native/jni/include)` to the CMakeLists.txt. – abggcv Jan 31 '18 at 13:32
  • May be it depends on how I am referring to opencv headers while including. I used standard way of referring to opencv headers: `#include ` – abggcv Jan 31 '18 at 13:34
  • @abggcv that is strange, I did not have it in my project. Here is an example: https://github.com/Fotoapparat/FaceDetector – Dmitry Zaytsev Jan 31 '18 at 13:55
  • 1
    Thanks @Dimitry I checked your repo and also I found you have a camera app code Fotoapparat. Is this better than the cwac, cwac2 camera apps for android? I am working on a camera app and would like to control camera features like focus and exposure etc. through the code. Is this something your repo could help with. Also, is your repo code solving the problems like rotated pics, display size etc. – abggcv Feb 01 '18 at 04:34
  • @Dimitry I could not get your facedector to run because I am not sure what path should I set for DJINNI_HOME – abggcv Feb 01 '18 at 06:47
  • 1
    @abggcv we developed Fotoapparat because we were not satisfied with cwac camera anymore. As for DJINNI_HOME - check this repo: https://github.com/dropbox/djinni – Dmitry Zaytsev Feb 01 '18 at 10:28
  • I am getting `undefined reference to cv::mat...` – code Feb 04 '18 at 12:25
  • 1
    @AbhishekSoni there is >1M things which can go wrong when working with C++. Please search for your specific problem. – Dmitry Zaytsev Feb 04 '18 at 20:31
  • 2
    This is the only solution I could find for building against and then using OpenCV libraries from C++ on Android that worked. Your FaceDetector application was a very useful reference for me in attempting to solve my problems. Thank you very much! – NickG Apr 11 '18 at 11:27
  • @DmitryZaytsev I have an error during findpackage(). It is looking in a directory that does not exist. Any clue ? –  Jun 07 '18 at 14:33
  • @DmitryZaytsev, I have placed a bounty on this related question: https://stackoverflow.com/q/44079701/897007 – Dale Sep 15 '19 at 00:53
0

Do same as Bruno Alexandre Krinski's Answer but

in place of this line

abiFilters 'x86', 'x86_64', 'armeabi', 'armeabi-v7a', 'arm64-v8a', 'mips', 'mips64'

put this line, (I don't know why this worked for me)

abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a'

(Follow all the instructions of above answer except this)

0

ABIs [armeabi] are not supported for Android platform

Supported ABIs are [arm64-v8a, armeabi-v7a, x86, x86_64].

externalNativeBuild {
            cmake {
              //  cppFlags ""
                cppFlags "-std=c++11 -frtti -fexceptions"
               // abiFilters 'x86', 'x86_64', 'armeabi', 'armeabi-v7a', 'arm64-v8a', 'mips', 'mips64'
                abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a'
            }
        }
Shomu
  • 2,734
  • 24
  • 32