Android Studio + OpenCV JNI 中的 hello world

准备

OpenCV  http://opencv.org/downloads.html 选择 OpenCV for Android 下载解压



Android Studio 2.2.2 点击图标打开SDK Manager。选择SDK Tools ,勾选NDK ,点击Apply。要等一段时间下载,下载后的文件在<Android SDK>\ndk-bundle。



开始

创建一个Empty Activity项目。然后创建一个jni目录


在jni文件夹中再创建3个文件,Android.mk,Application.mk以及gray-process.cpp。

扫描二维码关注公众号,回复: 2141582 查看本文章

Android.mk:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

#opencv
OPENCV_CAMERA_MODULES:=on
OPENCV_INSTALL_MODULES:=on
#OPENCV_LIB_TYPE:=STATIC
OPENCV_LIB_TYPE := SHARED
include /Users/wolf/code/test/opencvTest1/native/jni/OpenCV.mk


LOCAL_SRC_FILES := gray-process.cpp
LOCAL_LDLIBS += -llog
LOCAL_MODULE := gray_process

include $(BUILD_SHARED_LIBRARY)

OPENCV_CAMERA_MODULES:=on 使用摄像头功能

OPENCV_INSTALL_MODULES:=on 自动将依赖的OpenCV的so库拷贝到libs目录下,然后才能自动打包到sdk中。

OPENCV_LIB_TYPE:=STATIC 通过静态的方式链接OpenCV的so,将STATIC改为SHARED,就是通过动态的方式链接,这涉及到最后生成so的大小

include /Users/wolf/code/test/opencvTest1/native/jni/OpenCV.mk  指向你的OpenCV Android SDK中对应文件的位置,OpenCV Android SDK你可以放在电脑的任意位置。

             OpenCV.mk 文件可以打开看一看,里面会有需要判断 OPENCV_LIB_TYPE或OPENCV_INSTALL_MODULES来执行一些操作

LOCAL_LDLIBS += -llog 链接本地动态库 可以通过__android_log_print在ndk中打印日志

LOCAL_MODULE := opencv_gray_process 生成库的名字

LOCAL_SRC_FILES := gray-process.cpp 编译so所需要包含的文件,如果有多个文件就 LOCAL_SRC_FILES += 文件名 


Application.mk

APP_CPPFLAGS := -frtti -fexceptions -std=c++11
APP_STL := gnustl_static
APP_ABI := armeabi-v7a x86
APP_PLATFORM := android-16


gray-process.cpp

//
// Created by wolf on 16/11/17.
//
#include <jni.h>
#include <stdio.h>
#include <stdlib.h>
#include <opencv2/opencv.hpp>


#include <android/log.h>


#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
#define LOG_TAG "opencv_gray_process"
#define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))

using namespace std;
using namespace cv;
extern "C" {
static jintArray OpenCVHelper_gray
        (JNIEnv *env, jclass obj, jintArray buf, int w, int h){

    jboolean ptfalse = false;
    jint* srcBuf = env->GetIntArrayElements(buf, &ptfalse);
    if(srcBuf == NULL){
        return 0;
    }
    int size=w * h;

    LOGD("w: %d h: %d",w,h);
    Mat srcImage(h, w, CV_8UC4, (unsigned char*)srcBuf);
    Mat grayImage;
    cvtColor(srcImage, grayImage, COLOR_BGRA2GRAY);
    cvtColor(grayImage, srcImage, COLOR_GRAY2BGRA);

    jintArray result = env->NewIntArray(size);
    env->SetIntArrayRegion(result, 0, size, srcBuf);
    env->ReleaseIntArrayElements(buf, srcBuf, 0);
    return result;
}

#define JNIREG_CLASS "com/yanzhao/wolf/opencvtest1/OpenCVHelper"//指定要注册的类

static JNINativeMethod g_methods[] ={
        { "gray", "([III)[I", (void *) OpenCVHelper_gray },
};
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
{
    JNIEnv* env = NULL;
    jint result = -1;
    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
        return -1;
    }
    assert(env != NULL);

    jclass clazz = env->FindClass(JNIREG_CLASS);

    env->RegisterNatives(clazz, g_methods, NELEM(g_methods));

    return JNI_VERSION_1_4;
}
JNIEXPORT void JNI_OnUnload(JavaVM *jvm, void *reserved)
{

}
}
这里我采用了动态注册的方式,将c函数注册到了java类里。


OpenCVHelper.java

package com.yanzhao.wolf.opencvtest1;


/**
 * Created by wolf on 16/11/10.
 * e-mail : [email protected]
 */

public class OpenCVHelper {
    static {
        System.loadLibrary("gray-process");
    }
    public static native int[] gray(int[] buf, int w, int h);
  
}

然后就需要修改app目录下的build.gradle文件
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    sourceSets { main {
        jniLibs.srcDirs = ['src/main/libs', 'src/main/jniLibs']
        jni.srcDirs = []
    } }

    task ndkBuild(type: Exec, description: 'Compile JNI source with NDK') {
        Properties properties = new Properties()
        properties.load(project.rootProject.file('local.properties').newDataInputStream())
        def ndkDir = properties.getProperty('ndk.dir')

        if (org.apache.tools.ant.taskdefs.condition.Os.isFamily(org.apache.tools.ant.taskdefs.condition.Os.FAMILY_WINDOWS)) {
            commandLine "$ndkDir/ndk-build.cmd", '-C', file('src/main/jni').absolutePath
        } else {
            commandLine "$ndkDir/ndk-build", '-C', file('src/main/jni').absolutePath
        }
    }

    tasks.withType(JavaCompile) {
        compileTask -> compileTask.dependsOn ndkBuild
    }
    task ndkClean(type: Exec, description: 'Clean NDK Binaries') {
        Properties properties = new Properties()
        properties.load(project.rootProject.file('local.properties').newDataInputStream())
        def ndkDir = properties.getProperty('ndk.dir')

        if (org.apache.tools.ant.taskdefs.condition.Os.isFamily(org.apache.tools.ant.taskdefs.condition.Os.FAMILY_WINDOWS)) {
            commandLine "$ndkDir/ndk-build.cmd",'clean', '-C', file('src/main/jni').absolutePath
        } else {
            commandLine "$ndkDir/ndk-build",'clean', '-C', file('src/main/jni').absolutePath
        }
    }

    clean.dependsOn 'ndkClean'


现在可以点击ndkBuild来编译so文件了。或者通过终端 cd 到jni 目录下执行ndk-build命令。


下面是如何调用native函数

        Bitmap photo = bmp;
        int w = photo.getWidth();
        int h = photo.getHeight();
        int[] pixels = new int[w*h];
        photo.getPixels(pixels, 0, w, 0, 0, w, h);
        int[] resultInt = OpenCVHelper.gray(pixels, w, h);
        Bitmap resultImg = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        resultImg.setPixels(resultInt, 0, w, 0, 0, w, h);
        imageView.setImageBitmap(resultImg);








猜你喜欢

转载自blog.csdn.net/langzxz/article/details/53121554