13

I'm having trouble using native OpenCv 2.4.11 (3.0.0 is also ok) with Android Studio 1.3+, with new ndk support. All tutorials about .mk files, but I want to use it with new experimental gradle.
Using Kiran answer OpenCV in Android Studio I achived to work fine in java. Also I have changed
gradle-wrapper.properties:

distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-all.zip

build.gradle(application):

classpath 'com.android.tools.build:gradle-experimental:0.2.0'



build.gradle(module):

apply plugin: 'com.android.model.application'

model {
    android {
        compileSdkVersion = 23
        buildToolsVersion = "23.0.0"

        defaultConfig.with {
            applicationId = "android.overloaded.nativetestv4"
            minSdkVersion.apiLevel = 18
            targetSdkVersion.apiLevel = 23
            versionCode = 1
            versionName = "1.0"
        }
    }

    android.ndk{
        moduleName = "mymodule"
        ldLibs += ['log']
        cppFlags += "-std=c++11" 
        cppFlags += "-fexceptions"
        cppFlags  += "-I${file("C:/DevAndroid/OpenCV-android-sdk/sdk/native/jni/include")}".toString()
        cppFlags  += "-I${file("C:/DevAndroid/OpenCV-android-sdk/sdk/native/jni/include/opencv")}".toString()

        ldLibs += ["android", "EGL", "GLESv2", "dl", "log", "z"] //added z
        stl = "stlport_static"//"gnustl_shared" changed to stlport static
    }

    android.buildTypes {
        release {
            minifyEnabled = false
            proguardFiles += file('proguard-rules.pro')
        }
    }
    android.productFlavors { //added all productFlavors code
        create("arm") {
            ndk.with {
                abiFilters += "armeabi"
                File curDir = file('./')
                curDir = file(curDir.absolutePath)
                String libsDir = curDir.absolutePath+"\\src\\main\\jniLibs\\armeabi\\" //"-L" +
                ldLibs += libsDir + "libnative_camera_r4.3.0.so"
                ldLibs += libsDir + "libopencv_contrib.a"
                ldLibs += libsDir + "libopencv_core.a"
                ldLibs += libsDir + "libopencv_highgui.a"
                ldLibs += libsDir + "libopencv_imgproc.a"
                ldLibs += libsDir + "libopencv_info.so"
                ldLibs += libsDir + "libopencv_java.so"
                ldLibs += libsDir + "libopencv_legacy.a"
                ldLibs += libsDir + "libopencv_ml.a"
                ldLibs += libsDir + "libopencv_ts.a"
            }
        }
        create("armv7") {
            ndk.with {
                abiFilters += "armeabi-v7a"
                File curDir = file('./')
                curDir = file(curDir.absolutePath)
                String libsDir = curDir.absolutePath+"\\src\\main\\jniLibs\\armeabi-v7a\\" //"-L" +

               ldLibs += libsDir + "libnative_camera_r4.3.0.so"
               ldLibs += libsDir + "libopencv_contrib.a"
               ldLibs += libsDir + "libopencv_core.a"
               ldLibs += libsDir + "libopencv_highgui.a"
               ldLibs += libsDir + "libopencv_imgproc.a"
               ldLibs += libsDir + "libopencv_info.so"
               ldLibs += libsDir + "libopencv_java.so"
               ldLibs += libsDir + "libopencv_legacy.a"
               ldLibs += libsDir + "libopencv_ml.a"
               ldLibs += libsDir + "libopencv_ts.a"
            }
         }
         create("fat") {
         }
     }
    dependencies {
        compile fileTree(include: ['*.jar'], dir: 'libs')
        compile 'com.android.support:appcompat-v7:23.0.0'
        compile project(':openCVLibrary2411')
    }

With this changes I can call my native dummy function in c++ file under jni folder. Also #include <opencv2/core/core.hpp> and others are supported by CLion... When I declare cv::Mat mat; gives me this error:

Linker failed while linking libmymodule.so failed.
C:\DevAndroid\OpenCV-android-sdk\sdk\native\jni\include/opencv2/core/mat.hpp:278: error: undefined reference to 'cv::fastFree(void*)'
C:\DevAndroid\OpenCV-android-sdk\sdk\native\jni\include/opencv2/core/mat.hpp:367: error: undefined reference to 'cv::Mat::deallocate()'
collect2.exe: error: ld returned 1 exit status

c++ code:

#include <jni.h>
#include <vector>
#include <string>
#include "helpers.h"
#include <opencv2/core/core.hpp> //This is supported by CLion
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace std;

extern "C" {
JNIEXPORT jstring JNICALL
Java_android_overloaded_nativetestv4_MainActivity_FuncV1(JNIEnv *env, jclass type) {
    cv::Mat mat; //causing error

    string s = "Cpp v1 - succ ";
    return env->NewStringUTF(s.data());
}

}

Update

- added "z" to ldLibs
- added android.productFlavors block

Now compilation is successfull, application starts for second and then crashes with this messages
Event log:

IllegalArgumentException: Error while starting native debug session: Unable to find process for android.overloaded.nativetestv4 on device huawei-huawei_y530_u00-64a6513ccd8e

Debug info:

Restart ADB integration and try again
Waiting for process: android.overloaded.nativetestv4
DEVICE SHELL COMMAND: run-as android.overloaded.nativetestv4 mkdir -p /data/data/android.overloaded.nativetestv4/lldb/bin
DEVICE SHELL COMMAND: cat /data/local/tmp/lldb-server | run-as android.overloaded.nativetestv4 sh -c 'cat > /data/data/android.overloaded.nativetestv4/lldb/bin/lldb-server; chmod 700 /data/data/android.overloaded.nativetestv4/lldb/bin/lldb-server'
DEVICE SHELL COMMAND: rm /data/local/tmp/lldb-server
DEVICE SHELL COMMAND: cat /data/local/tmp/start_lldb_server.sh | run-as android.overloaded.nativetestv4 sh -c 'cat > /data/data/android.overloaded.nativetestv4/lldb/bin/start_lldb_server.sh; chmod 700 /data/data/android.overloaded.nativetestv4/lldb/bin/start_lldb_server.sh'
DEVICE SHELL COMMAND: rm /data/local/tmp/start_lldb_server.sh
Now Launching Native Debug Session
Error while starting native debug session: java.lang.IllegalArgumentException: Unable to find process for android.overloaded.nativetestv4 on device huawei-huawei_y530_u00-64a6513ccd8e

log:

A/libc﹕ Fatal signal 11 (SIGSEGV) at 0x00000000 (code=1), thread 3077 (ed.nativetestv4)
Jeru Luke
  • 20,118
  • 13
  • 80
  • 87
Petar P
  • 368
  • 4
  • 13
  • 1
    You're pointing to the location of the headers, but not to the location of the actual libraries. Including '-L' and then the names of the libraries you are using in the ldLibraries should work. – user1906 Aug 23 '15 at 23:07
  • There are .so and .a in directories: src/main/jniLibs/. Isn't that enough? I'm newbie in android and I don't understand much what is happening in gradle files. – Petar P Aug 24 '15 at 09:57

1 Answers1

20

After few weeks of pain, I succed. Here is my correct code for Android studio 1.3.1, OpenCv 2.4.11. First you should do this OpenCV in Android Studio (don't use paths which contains white space, both for project and opencv extraction folder) then, for opencv to be native:

gradle-wrapper.properties:

distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-all.zip 

build.gradle(application):

classpath 'com.android.tools.build:gradle-experimental:0.2.0'

build.gradle(module):

apply plugin: 'com.android.model.application'

model {
    android {
        compileSdkVersion = 23
        buildToolsVersion = "23.0.0"

        defaultConfig.with {
            applicationId = "android.overloaded.nativetestv4"
            minSdkVersion.apiLevel = 18
            targetSdkVersion.apiLevel = 23
            versionCode = 1
            versionName = "1.0"
        }
    }


    android.ndk{
        moduleName = "mymodule"
        ldLibs += ['log']
        cppFlags += "-std=c++11"
        cppFlags += "-fexceptions"
        cppFlags  += "-I${file("C:/DevAndroid/OpenCV-android-sdk/sdk/native/jni/include")}".toString()
        cppFlags  += "-I${file("C:/DevAndroid/OpenCV-android-sdk/sdk/native/jni/include/opencv")}".toString()



//        ldFlags += linkOpt
        ldLibs += ["android", "EGL", "GLESv2", "dl", "log", "z"]// , "ibopencv_core"
        stl = "gnustl_shared"//"gnustl_static"//"gnustl_shared"//"stlport_static"
    }

    android.buildTypes {
        release {
            minifyEnabled = false
            proguardFiles += file('proguard-rules.pro')
        }
    }

    android.productFlavors {
        create("arm") {
            ndk.with {
                abiFilters += "armeabi"

                File curDir = file('./')
                curDir = file(curDir.absolutePath)
                String libsDir = curDir.absolutePath+"\\src\\main\\jniLibs\\armeabi\\" //"-L" +

                ldLibs += libsDir + "libnative_camera_r4.3.0.so"
                ldLibs += libsDir + "libopencv_contrib.a"
                ldLibs += libsDir + "libopencv_core.a"
                ldLibs += libsDir + "libopencv_highgui.a"
                ldLibs += libsDir + "libopencv_imgproc.a"
                ldLibs += libsDir + "libopencv_info.so"
                ldLibs += libsDir + "libopencv_java.so"
                ldLibs += libsDir + "libopencv_legacy.a"
                ldLibs += libsDir + "libopencv_ml.a"
                ldLibs += libsDir + "libopencv_ts.a"

            }
        }
        create("armv7") {
            ndk.with {
                abiFilters += "armeabi-v7a"

                File curDir = file('./')
                curDir = file(curDir.absolutePath)
                String libsDir = curDir.absolutePath+"\\src\\main\\jniLibs\\armeabi-v7a\\" //"-L" +

                ldLibs += libsDir + "libnative_camera_r4.3.0.so"
                ldLibs += libsDir + "libopencv_contrib.a"
                ldLibs += libsDir + "libopencv_core.a"
                ldLibs += libsDir + "libopencv_highgui.a"
                ldLibs += libsDir + "libopencv_imgproc.a"
                ldLibs += libsDir + "libopencv_info.so"
                ldLibs += libsDir + "libopencv_java.so"
                ldLibs += libsDir + "libopencv_legacy.a"
                ldLibs += libsDir + "libopencv_ml.a"
                ldLibs += libsDir + "libopencv_ts.a"

            }
        }
        create("x86") {
            ndk.with {
                abiFilters += "x86"
            }
        }
        create("mips") {
            ndk.with {
                abiFilters += "mips"
            }
        }
        create("fat") {

        }
    }

}
dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    compile 'com.android.support:appcompat-v7:23.0.0'
    compile project(':openCVLibrary2411')
}

.cpp

#include <jni.h>
#include <vector>
#include <string>
#include "helpers.h"
#include <opencv2/core/core.hpp>

using namespace std;

#ifdef __cplusplus
extern "C" {
#endif



JNIEXPORT jstring JNICALL
Java_android_overloaded_nativetestv4_MainActivity_FuncV1(JNIEnv *env, jclass type) {

    cv::Mat mat(33,22, 1);

    string s = "Cpp v1 - succ, rows#:" + Helpers::ToStringNum(mat.rows);
    Helpers::Log(s);

    return env->NewStringUTF(s.data());
}

}

.java

package android.overloaded.nativetestv4;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity
{
    static {
        System.loadLibrary("mymodule");
    }

    public static native String FuncV1();

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toast.makeText(this, FuncV1(), Toast.LENGTH_LONG).show();

        ((TextView)findViewById(R.id.txtInfo)).setText(FuncV1());
    }

Update for Android Studio 1.5.1, OpenCV 3.1
1. First you should do this OpenCV in Android Studio (don't use paths which contains white space, both for project and opencv extraction folder), after that you should have normal working Java app
2. Change build.gradle in project root:

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath "com.android.tools.build:gradle-experimental:0.4.0"

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}
  1. Change gradle-wrapper.properties:
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-all.zip
  1. Change build.gradle in opencv module:

    apply plugin: 'com.android.model.library'
    
    model {
        android {
            compileSdkVersion = 23
            buildToolsVersion = "23.0.2"
            defaultConfig.with {
                minSdkVersion.apiLevel = 11
                targetSdkVersion.apiLevel = 23
            }
    
    
        }
    
        android.buildTypes {
            release {
                minifyEnabled = false
                proguardFiles.add(file("proguard-rules.txt"))
            }
        }
    }
    
  2. Change build.gradle in app module:

    apply plugin: 'com.android.model.application'
    
    model {
        android {
            compileSdkVersion = 23
            buildToolsVersion = "23.0.2"
    
            defaultConfig.with {
                applicationId = "android.overloaded.opencv31v1" //Name of package
                minSdkVersion.apiLevel = 11
                targetSdkVersion.apiLevel = 23
                versionCode = 1
                versionName = "1.0"
    
            }
        }
    
        android.ndk {
            moduleName = "native" // Name of C++ module, for System.loadLibrary("native")
            cppFlags.add("-std=c++11") // Add provisions to allow C++11 functionality
            cppFlags.add("-fexceptions")
            // YOUR OPENCV DIRECTORY!!!
            cppFlags.add("-I${file("C:/DevAndroid/OpenCV-android-sdk/sdk/native/jni/include")}".toString()) 
            ldLibs.addAll(["android", "EGL", "GLESv2", "dl", "log", "z"])
            stl = "gnustl_shared"
        }
    
        android.buildTypes {
            release {
                minifyEnabled = false
                proguardFiles.add(file("proguard-rules.txt"))
            }
        }
    
        android.productFlavors {
            create("arm") {
                ndk.with{
                    abiFilters.add("armeabi")
    
                    File curDir = file('./')
                    curDir = file(curDir.absolutePath)
                    String libsDir = curDir.absolutePath + "\\src\\main\\jniLibs\\armeabi\\"
    
                    ldLibs.add(libsDir + "libopencv_core.a")
                    ldLibs.add(libsDir + "libopencv_highgui.a")
                    ldLibs.add(libsDir + "libopencv_imgproc.a")
                    ldLibs.add(libsDir + "libopencv_java3.so")
                    ldLibs.add(libsDir + "libopencv_ml.a")
    
                }
            }
            create("armv7") {
                ndk.with {
                    abiFilters.add("armeabi-v7a")
    
                    File curDir = file('./')
                    curDir = file(curDir.absolutePath)
                    String libsDir = curDir.absolutePath + "\\src\\main\\jniLibs\\armeabi-v7a\\"
                    ldLibs.add(libsDir + "libopencv_core.a")
                    ldLibs.add(libsDir + "libopencv_highgui.a")
                    ldLibs.add(libsDir + "libopencv_imgproc.a")
                    ldLibs.add(libsDir + "libopencv_java3.so")
                    ldLibs.add(libsDir + "libopencv_ml.a")
                    ldLibs.add(libsDir + "libopencv_ts.a")
    
                }
            }
        }
        android.sources{
            main{
                jni{
                    source{
                        srcDirs += ['src/main/jniMy']
                    }
                }
            }
        }
    }
    dependencies {
        compile fileTree(dir: "libs", include: [$/*.jar/$])
        compile "com.android.support:appcompat-v7:23.1.1" //Do not use 23.2.0 
        compile project(":openCVLibrary310")
    }
    
  3. Create dir app/src/main/jniMy, this is place for yours .cpp files

  4. Optionally create file chelper.c in jniMy, with this code:

    #ifndef OPENCV31V1_CHELPER_H
    #define OPENCV31V1_CHELPER_H
    
    #include <jni.h>
    #include <vector>
    #include <string>
    #include <sstream>
    #include <android/log.h>
    
    using namespace std;
    
    class Helpers{
    public:
        template <typename T>
        static string ToStringNum(T tNumber){
            ostringstream ostrStream;
            ostrStream << tNumber;
            return ostrStream.str();
        }
    
        static void Log(string s){
            __android_log_print(ANDROID_LOG_INFO, "My", s.data());
        }
        static void Log(std::exception ee){
            string s = "Exception: " + string(ee.what()) ;
            __android_log_print(ANDROID_LOG_INFO, "My", s.data());
        }
    
        static long Time(){
            struct timespec now;
            clock_gettime(CLOCK_MONOTONIC, &now);
            return (long)((int64_t)now.tv_sec * 1000LL + now.tv_nsec /1000000LL);
        }
        static string Time(long iTime){
            return ToStringNum(Time() - iTime) + "ms";
        }
    
    };
    #endif //OPENCV31V1_CHELPER_H
    
  5. Create file native_exporter.cpp in jniMy, with this code:

    #include <jni.h>
    #include <string>
    #include <opencv2/core/core.hpp>
    #include "chelper.h"
    
    extern "C"{
    JNIEXPORT jstring     JNICALLJava_android_overloaded_opencv31v1_MainActivity_FuncV1(JNIEnv *env,
    jclass type) {
    
        cv::Mat mat(33,22, CV_32FC2);
    
        string s = "Cpp v1 - succ, rows#:" +Helpers::ToStringNum(mat.rows);
        Helpers::Log(s);
        auto i = 5;
        for (int i2 : {1,3,5}){
            Helpers::Log(Helpers::ToStringNum(i2));
        }
    
        return env->NewStringUTF(s.data());
    }
    }
    
  6. Code in MainActivity.java:

    package android.overloaded.opencv31v1;
    
    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    import android.util.Log;
    import android.view.SurfaceView;
    import android.widget.TextView;
    import android.widget.Toast;
    
    import org.opencv.android.CameraBridgeViewBase;
    import org.opencv.core.CvType;
    import org.opencv.core.Mat;
    
    public class MainActivity extends AppCompatActivity implements CameraBridgeViewBase.CvCameraViewListener2
    {
        private static void Log(String sMsg){Log.i("My", "MainActivity." + sMsg );}
    
        static{
            System.loadLibrary("opencv_java3");
            System.loadLibrary("native");
        }
    
        public native String FuncV1();
        JavaCameraViewCustom2 _javaCameraView; //Similar to JavaCameraView
    
        @Override
        protected void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            if(getSupportActionBar() != null)getSupportActionBar().hide();
            String sRes = FuncV1();
            Toast.makeText(this, sRes, Toast.LENGTH_LONG).show();
    
            ((TextView)findViewById(R.id.txtInfo)).setText(sRes);
    
            _javaCameraView = (JavaCameraViewCustom2)findViewById(R.id.cameraView);
            _javaCameraView.setVisibility(SurfaceView.VISIBLE);
            _javaCameraView.setCvCameraViewListener(this);
    
        }
    
        @Override
        protected void onResume()
        {
            super.onResume();
            _javaCameraView.enableView();
        }
    
        @Override
        protected void onPause()
        {
            super.onPause();
            _javaCameraView.disableView();
        }
    
        Mat _imgBgrTemp;
        @Override
        public void onCameraViewStarted(int width, int height)
        {
            _imgBgrTemp = new Mat(height,width, CvType.CV_8UC4);
        }
    
        @Override
        public void onCameraViewStopped()
        {
            _imgBgrTemp.release();
        }
    
        @Override
        public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame)
        {
            _imgBgrTemp = inputFrame.rgba();
            return _imgBgrTemp;
        }
    }  
    

Android Studio will ask you to change jdk, also it will install new gradle, you should do everything it ask.

Community
  • 1
  • 1
Petar P
  • 368
  • 4
  • 13
  • Hi I'm having trouble with the ` OpenCV Error: Bad argument (Specified descriptor extractor type is not supported.) in static cv::javaDescriptorExtractor* cv::javaDescriptorExtractor::create(int), file /builds/master_pack-android/opencv/modules/features2d/misc/java/src/cpp/features2d_manual.hpp, line 374` can you help me with this? – JoeG Sep 07 '15 at 05:55
  • I found this page about BRIEF bug http://code.opencv.org/issues/4419 in Opencv 3.0. Maybe other Descriptors/Extractors are also affected. You could try to use constructor: BriefDescriptorExtractor brief = BriefDescriptorExtractor(32); – Petar P Sep 07 '15 at 06:58
  • What do you mean by (module) and (application) ? Module = openCVLibrary and Application = app ? Or application is the project's build.gradle ? Ty! – Geraldo Neto Jan 08 '16 at 03:26
  • Also, I'm having problem with the #include "helpers.h" What exactly is this ? – Geraldo Neto Jan 08 '16 at 04:39
  • 1
    @GeraldoNeto Header file helpers.h contains just functions for logging. I created that file, it's unimportant, just delete '#include "helpers.h"'. – Petar P Jan 12 '16 at 23:26