Android Studio 2.1.3 在gradle-experimental下编译使用OpenCV

Android Studio 2.1.3 在gradle-experimental下编译使用OpenCV

Android Studio 进行jni的编程时有个实验性的gradle-experimental,用起来还是比较方便,不需要编写Android.mk文件和Application.mk文件,所有的配置的在app/build.gradle中完成,而且C++代码也可以自动提示。本文以编译使用OpenCV为示例,讲解Android Studio NDK开放环境的配置。

使用的开放环境如下:

  • Android Studio 2.1.3
  • gradle版本为:2.14
  • gradle-experimental版本为:0.7.3
  • OpenCV的版本为:3.1.0

新建工程

在AS中新建一Android工程,名字随意,我已OpenCV为工程名。

安装NDK

使用AS自带的NDK,因此第一步需要下载NDK。打开File >Settings>Appearance & Behavior > System Settings > Android SDK。在界面左边选择SDK Tools 选择NDK选项,如果没安装,点击OK后,系统便会进行NDK的按照。如下图所示:
这里写图片描述

按照完毕后打开File > Project Structrue > SDK Location,在右边的界面中 Android NDK Location 一栏中会显示安装的NDK路径,如下图所示:
这里写图片描述

修改工程目录下的build.gradle

打开工程名/build.gradle,注意不是app/build.gradle。将默认的
classpath ‘com.android.tools.build:gradle:2.1.3’ 修改为:
classpath ‘com.android.tools.build:gradle-experimental:0.7.3’
整个文件内容如下:
这里写图片描述
修改完成后进行sync会出现错误提示,正是下一步需要解决的问题。

注意:如果使用的不是gradle-experimental:0.7.3,则还需修改gradle的版本。打开File->Project Strcutrue->Project 在界面右边修改Gradle version的版本,以适合gradle-experimental的版本。

修改app/build.gradle

因为使用的的gradle-experimental,原有的build.gradle就不适用了,需要进行修改。基本的就将
apply plugin: ‘com.android.application’ 修改为:
apply plugin: ‘com.android.model.application’
在原有的android节点外添加model节点,使model节点包含android节点,并且原有的属性配置需要添加等号。如下所示:

model {
    android {
        compileSdkVersion = 24
        buildToolsVersion = "24.0.1"

        defaultConfig.with {
            applicationId = "com.leej.opencv"
            minSdkVersion.apiLevel = 14
            targetSdkVersion.apiLevel =  24
            versionCode = 1
            versionName = "1.0"
        }
    }

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

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:24.1.0'
}

截至这里基本的配置完成,下面就是ndk的配置和OpenCV的编译使用了。

下载OpenCV for Android

到这里http://opencv.org/platforms/android.html下载OpenCV for Android 的合适版本。下载后解压,拷贝..\OpenCV-android-sdk\sdk\native 文件夹到建立的Android项目工程目录下。整个的工程目录结构如下:
这里写图片描述

创建JNI文件夹

在app/src/main下创建jni文件夹,本地C++文件都存于次,创建的方法如下:
这里写图片描述

NDK的配置

在gradle-experimental下,需在app/build.gradle中添加相应的配置,才能正确编译本地方法。
在model节点下添加:

android.ndk {
    moduleName = "myOpenCV"
    cppFlags.add("-std=c++11")
    cppFlags.add("-frtti")
    cppFlags.add("-fexceptions")
    cppFlags.add("-I${file("../native/jni/include")}".toString())
    cppFlags.add("-I${file("../native/jni/include/opencv")}".toString())
    ldLibs.addAll(["android", "EGL", "GLESv2", "dl", "log", "z"]) //编译需要
    stl = 'gnustl_shared' //能够实现C++代码自动提示的关键
}

android.productFlavors {
    create("arm") {
        ndk.with {
            abiFilters.add("armeabi")
            String libsDir = getProjectDir().getParent() + "\\native\\libs\\armeabi\\"
            String thirdPartyDir = getProjectDir().getParent() + "\\native\\3rdparty\\libs\\armeabi\\"

            ldFlags.add(libsDir + "libopencv_features2d.a")
            ldFlags.add(libsDir + "libopencv_flann.a")
            ldFlags.add(libsDir + "libopencv_imgproc.a")
            ldFlags.add(libsDir + "libopencv_core.a")
            ldFlags.add(libsDir + "libopencv_highgui.a")
            ldFlags.add(libsDir + "libopencv_calib3d.a")//注意添加的先后顺序
            ldFlags.add(thirdPartyDir + "libtbb.a")
        }
    }
    create("armv7") {
        ndk.with {
            abiFilters.add("armeabi-v7a")
            String libsDir = getProjectDir().getParent() + "\\native\\libs\\armeabi-v7a\\";
            String thirdPartyDir = getProjectDir().getParent() + "\\native\\3rdparty\\libs\\armeabi-v7a\\";

            ldFlags.add(libsDir + "libopencv_features2d.a")
            ldFlags.add(libsDir + "libopencv_flann.a")
            ldFlags.add(libsDir + "libopencv_imgproc.a")
            ldFlags.add(libsDir + "libopencv_core.a")
            ldFlags.add(libsDir + "libopencv_highgui.a")
            ldFlags.add(libsDir + "libopencv_calib3d.a")
            ldFlags.add(thirdPartyDir + "libtbb.a")
        }
    }
    create("x86") {
        ndk.with {
            abiFilters.add("x86")
            String libsDir = getProjectDir().getParent() + "\\native\\libs\\x86\\";
            String thirdPartyDir = getProjectDir().getParent() + "\\native\\3rdparty\\libs\\x86\\";

            ldFlags.add(libsDir + "libopencv_features2d.a")
            ldFlags.add(libsDir + "libopencv_flann.a")
            ldFlags.add(libsDir + "libopencv_imgproc.a")
            ldFlags.add(libsDir + "libopencv_core.a")
            ldFlags.add(libsDir + "libopencv_highgui.a")
            ldFlags.add(libsDir + "libopencv_calib3d.a")
            ldFlags.add(thirdPartyDir + "libtbb.a")
        }
    }
}

完成之后整个app/build.gradle文件为:

model {
    android {
        compileSdkVersion = 24
        buildToolsVersion = "24.0.1"

        defaultConfig.with {
            applicationId = "com.leej.opencv"
            minSdkVersion.apiLevel = 14
            targetSdkVersion.apiLevel =  24
            versionCode = 1
            versionName = "1.0"
        }
    }

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

    android.ndk {
        moduleName = "myOpenCV"
        cppFlags.add("-std=c++11")
        cppFlags.add("-frtti")
        cppFlags.add("-fexceptions")
        cppFlags.add("-I${file("../native/jni/include")}".toString())
        cppFlags.add("-I${file("../native/jni/include/opencv")}".toString())
        ldLibs.addAll(["android", "EGL", "GLESv2", "dl", "log", "z"]) //编译需要
        stl = 'gnustl_shared' //能够实现C++代码自动提示的关键
    }

    android.productFlavors {
        create("arm") {
            ndk.with {
                abiFilters.add("armeabi")
                String libsDir = getProjectDir().getParent() + "\\native\\libs\\armeabi\\"
                String thirdPartyDir = getProjectDir().getParent() + "\\native\\3rdparty\\libs\\armeabi\\"

                ldFlags.add(libsDir + "libopencv_features2d.a")
                ldFlags.add(libsDir + "libopencv_flann.a")
                ldFlags.add(libsDir + "libopencv_imgproc.a")
                ldFlags.add(libsDir + "libopencv_core.a")
                ldFlags.add(libsDir + "libopencv_highgui.a")
                ldFlags.add(libsDir + "libopencv_calib3d.a")//注意添加的先后顺序
                ldFlags.add(thirdPartyDir + "libtbb.a")
            }
        }
        create("armv7") {
            ndk.with {
                abiFilters.add("armeabi-v7a")
                String libsDir = getProjectDir().getParent() + "\\native\\libs\\armeabi-v7a\\";
                String thirdPartyDir = getProjectDir().getParent() + "\\native\\3rdparty\\libs\\armeabi-v7a\\";

                ldFlags.add(libsDir + "libopencv_features2d.a")
                ldFlags.add(libsDir + "libopencv_flann.a")
                ldFlags.add(libsDir + "libopencv_imgproc.a")
                ldFlags.add(libsDir + "libopencv_core.a")
                ldFlags.add(libsDir + "libopencv_highgui.a")
                ldFlags.add(libsDir + "libopencv_calib3d.a")
                ldFlags.add(thirdPartyDir + "libtbb.a")
            }
        }
        create("x86") {
            ndk.with {
                abiFilters.add("x86")
                String libsDir = getProjectDir().getParent() + "\\native\\libs\\x86\\";
                String thirdPartyDir = getProjectDir().getParent() + "\\native\\3rdparty\\libs\\x86\\";

                ldFlags.add(libsDir + "libopencv_features2d.a")
                ldFlags.add(libsDir + "libopencv_flann.a")
                ldFlags.add(libsDir + "libopencv_imgproc.a")
                ldFlags.add(libsDir + "libopencv_core.a")
                ldFlags.add(libsDir + "libopencv_highgui.a")
                ldFlags.add(libsDir + "libopencv_calib3d.a")
                ldFlags.add(thirdPartyDir + "libtbb.a")
            }
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:24.1.0'
}

编写本地方法

创建一个新的类编写两个本方法,如下图所示:
这里写图片描述

“myOpenCV”是生成的库文件的名字,与app/build.gradle 中的moduleName名字相同。getStringFromNative方法测试由C++来创建字符串;gray方法测试OpenCV的边缘检测。从图中可以看到标注为红色的方法, 将光标定位到getStringFromNative方法,并按快捷键Alt + Enter,此时会弹出下图的提示:
这里写图片描述

在弹出的框中点击第一项,会在jni文件中创建一个.c的文件,并且会创建一个本地方法,如下图所示:
这里写图片描述

注意:由于示例需要使用OpenCV,因此将.c文件改成了.cpp文件。

另外一个方法也采用同样的方式生成。
完成后的.cpp文件的内容如下:

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

using namespace std;
using namespace cv;

IplImage* change4ChannelTo3InIplImage(IplImage * src);

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

    // TODO

    Mat mat(33, 22, 1);

    string s = "Cpp v1 - succ, row#:" + mat.rows;

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

JNIEXPORT jintArray JNICALL
Java_com_leej_opencv_lib_OpenCV_gray(JNIEnv *env, jobject instance, jintArray buf_, jint w, jint h) {
    jint *buf = env->GetIntArrayElements(buf_, false);

    if (buf == NULL)
        return 0;

    Mat myImg(h, w, CV_8UC4, (unsigned char *)buf);
    IplImage image = IplImage(myImg);
    IplImage* image3Channel = change4ChannelTo3InIplImage(&image);

    IplImage* pCannyImage = cvCreateImage(cvGetSize(image3Channel), IPL_DEPTH_8U, 1);

    cvCanny(image3Channel, pCannyImage, 50, 150, 3);

    int* outImage = new int[w * h];

    for (int i = 0; i < w * h; i ++) {
        outImage[i] = (int)pCannyImage->imageData[i];
    }

    int size = w * h;
    jintArray result = env->NewIntArray(size);
    env->SetIntArrayRegion(result, 0, size, outImage);
    // TODO
    env->ReleaseIntArrayElements(buf_, buf, 0);

    return result;
}

IplImage* change4ChannelTo3InIplImage(IplImage * src) {
    if (src -> nChannels != 4) {
        return NULL;
    }

    IplImage* destImg = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 3);
    for (int row = 0; row < src->height; row ++) {
        for (int col = 0; col < src -> width; col ++) {
            CvScalar s = cvGet2D(src, row, col);
            cvSet2D(destImg, row, col, s);
        }
    }

    return destImg;
}

编译

点击Build-> Make Project对工程进行编译,在配置都正确的情况下,编译是成功的。

至此ndk的配置和OpenCV的使用就到此结束。可以自行编写程序测试这个方法是否成功,本人测试以通过。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值