Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android Studio 2.1.3 在gradle-experimental下編譯使用OpenCV

Android Studio 2.1.3 在gradle-experimental下編譯使用OpenCV

編輯:關於Android編程

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會出現錯誤提示,正是下一步需要解決的問題。<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxibG9ja3F1b3RlPg0KCTxwPtei0uKjusjnufvKudPDtcSyu8rHZ3JhZGxlLWV4cGVyaW1lbnRhbDowLjcuM6Os1PK7udDo0N64xGdyYWRsZbXEsOaxvqGjtPK/qkZpbGUtJmd0O1Byb2plY3QgU3RyY3V0cnVlLSZndDtQcm9qZWN0INTavefD5tPSsd/Q3rjER3JhZGxlIHZlcnNpb261xLDmsb6jrNLUysq6z2dyYWRsZS1leHBlcmltZW50YWy1xLDmsb6hozwvcD4NCjwvYmxvY2txdW90ZT4NCjxoMyBpZD0="修改appbuildgradle">修改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 
#include 
#include 
#include 
#include 

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的使用就到此結束。可以自行編寫程序測試這個方法是否成功,本人測試以通過。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved