OpenCv with Android studio 1.3+ using new gradle - undefined reference

Posted

技术标签:

【中文标题】OpenCv with Android studio 1.3+ using new gradle - undefined reference【英文标题】: 【发布时间】:2015-11-17 05:23:49 【问题描述】:

我在使用原生 OpenCv 2.4.11(3.0.0 也可以)和 android Studio 1.3+ 以及新的 ndk 支持时遇到问题。所有关于 .mk 文件的教程,但我想将它与新的实验性 gradle 一起使用。 使用 Kiran 回答 OpenCV in Android Studio 我在java中实现了正常工作。我还更改了 gradle-wrapper.properties: distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-all.zip build.gradle(应用程序):

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')
    

通过这些更改,我可以在 jni 文件夹下的 c++ 文件中调用我的原生虚拟函数。 CLion 还支持#include <opencv2/core/core.hpp> 和其他人...当我声明 cv::Mat mat;给我这个错误:

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++代码:

#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());



更新 - 将“z”添加到 ldLibs - 添加了 android.productFlavors 块

现在编译成功,应用程序启动第二次,然后崩溃并显示此消息 事件日志:

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

调试信息:

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

日志:

A/libc﹕ Fatal signal 11 (SIGSEGV) at 0x00000000 (code=1), thread 3077 (ed.nativetestv4)

【问题讨论】:

您指向的是标题的位置,而不是实际库的位置。包括“-L”,然后是您在 ldLibraries 中使用的库的名称。 目录中有.so和.a:src/main/jniLibs/。这还不够吗?我是 android 新手,我不太了解 gradle 文件中发生了什么。 【参考方案1】:

经过几周的痛苦,我成功了。这是我对 Android Studio 1.3.1、OpenCv 2.4.11 的正确代码。首先你应该这样做OpenCV in Android Studio (不要使用包含空格的路径,用于项目和 opencv 提取文件夹)然后,让 opencv 成为本机:

gradle-wrapper.properties:

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

build.gradle(应用程序):

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

build.gradle(模块):

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());
    

Android Studio 1.5.1、OpenCV 3.1 更新 1.首先你应该这样做OpenCV in Android Studio(不要使用包含空格的路径,用于项目和opencv提取文件夹),之后你应该有正常工作的Java应用程序 2.修改项目根目录下的build.gradle:

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

    更改 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

    修改opencv模块中的build.gradle:

    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"))
            
        
    
    

    在应用模块中更改 build.gradle:

    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")
    
    

    创建目录 app/src/main/jniMy,这是存放你的 .cpp 文件的地方

    可选择在 jniMy 中创建文件 chelper.c,使用以下代码:

    #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
    

    在 jniMy 中创建文件 native_exporter.cpp,使用以下代码:

    #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());
    
    
    

    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 会要求你更改 jdk,它还会安装新的 gradle,你应该做它要求的一切。

【讨论】:

您好,我在静态 cv::javaDescriptorExtractor* cv::javaDescriptorExtractor::create(int) 中遇到了`OpenCV 错误:错误参数(不支持指定的描述符提取器类型。),文件/builds/master_pack-android/opencv/modules/features2d/misc/java/src/cpp/features2d_manual.hpp,第374行你能帮我吗? 我在 Opencv 3.0 中找到了关于 Brief bug code.opencv.org/issues/4419 的页面。也许其他描述符/提取器也受到影响。您可以尝试使用构造函数:BriefDescriptorExtractor brief = BriefDescriptorExtractor(32); (模块)和(应用程序)是什么意思?模块 = openCVLibrary 和应用程序 = 应用程序?或者应用程序是项目的 build.gradle ?泰! 另外,#include "helpers.h" 有问题,这到底是什么? @GeraldoNeto 头文件 helpers.h 仅包含日志记录功能。我创建了那个文件,它不重要,只需删除 '#include "helpers.h"'。

以上是关于OpenCv with Android studio 1.3+ using new gradle - undefined reference的主要内容,如果未能解决你的问题,请参考以下文章

[Python Study Notes]with的使用

关于CMake编译OpenCV时opencv_ffmpeg.dllippicv等下载失败的解决办法及感悟

[CC-CHEFGRPH]Time to Study Graphs with Chef

Android OpenCV - 闭眼检测

回眸Study with me!计算机二/三 级(物联网)刷题的心路历程

在 Python OpenCV 中创建 FlowMap