Wednesday, November 23, 2016

Android中使用JNI調用Opencv本地代碼配置方式邊緣檢測

在Android中使用Opencv有兩種方式,一種是使用opencv的Java版本的API,但是這種方式不是通過本地調用實現的,全部都是java代碼,所以這裡先不講,另外一種方式就是使用opencv的c++版本的API,將本地c++代碼編譯成.so鏈接庫,然後在安卓開發中進行調用,本地cpp代碼使用NDK進行編譯。

下面給出一個使用Canny算子檢測邊緣的本地代碼調用的使用方式。
新建Android Prject,這裡我的項目名稱為HaveImgFun

然後修改界面控製文件res->layout->activity_have_img_fun.xml

activity_have_img_fun.xml code

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<Button android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:id="@+id/btnNDK"
android:text="使用C++ OpenCV进行处理" />
<Button android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:id="@+id/btnRestore"
android:text="还原" />

<TextView
android:text="TextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/textView2" />

<ImageView android:id="@+id/ImageView01"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</LinearLayout>


在文件夾src下的com.XXX.haveimgfun包中新建一個類用於包裝使用了opencv c++代碼的動態庫的導出函數,類名為LibImgFun。 Android Studio會為你創建一個新的文件LibImgFun.java,將裡面的內容改為:

package com.example.cheng.haveimgfun;

/**
* Created by Cheng on 2016/11/23.
*/

public class LibImgFun {
static {
System.loadLibrary("ImgFun");
}

public static native int[] ImgFun(int[] buf, int w, int h);
public native String getMycstring();
}
從上面的代碼可以得知,我們的動態庫名字應該為“libImgFun.so”。
注意"public static native int[] ImgFun(int[] buf, int w, int h)"中的native關鍵字,表明這個函數來自native code。static表示這是一個靜態函數,這樣就可以直接用類名去調用

建立C++代碼


在項目中新建一個jni文件,用於放置該項目的所有cpp代碼。
在jni文件夾下建立一個"ImgFun.cpp"的文件,內容改為下面所示:

//
// Created by Cheng on 2016/11/23.
//
//
// Created by Cheng on 2016/11/23.
//
#include <stdio.h>
#include <stdlib.h>
#include <opencv2/opencv.hpp>
#include "com_example_cheng_haveimgfun_LibImgFun.h"
JNIEXPORT jstring JNICALL Java_com_example_cheng_haveimgfun_LibImgFun_getMycstring
(JNIEnv * evn, jobject obj) {
return ( * evn).NewStringUTF("Hello NKD demo");
}
using namespace cv;
IplImage * change4channelTo3InIplImage(IplImage * src);

extern "C" {

JNIEXPORT jintArray JNICALL Java_com_example_cheng_haveimgfun_LibImgFun_ImgFun
(JNIEnv * env, jobject obj, jintArray buf, jint w, jint h) {

jint * cbuf;
cbuf = env - > GetIntArrayElements(buf, NULL);
printf("%d",cbuf);
if (cbuf == NULL) {
return 0;
}

Mat myimg(h, w, CV_8UC4, (unsigned char * ) cbuf);
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);
env - > ReleaseIntArrayElements(buf, cbuf, 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;
}

配置文件

然後再在jni下新建兩個文件"Android.mk"文件和"Application.mk"文件,這兩個文件事實上就是簡單的Makefile文件。

使用NDK進行編譯的時候,需要使用 Android.mk Application.mk 兩個文件。

Android.mk
LOCAL_PATH := $(call my-dir)    
include $(CLEAR_VARS)
OPENCV_LIB_TYPE:=STATIC
ifeq ("$(wildcard $(OPENCV_MK_PATH))","")
#try to load OpenCV.mk from default install location
include D:\OpenCV-android-sdk\sdk\native\jni\OpenCV.mk
else
include $(OPENCV_MK_PATH)
endif
LOCAL_MODULE := ImgFun
LOCAL_SRC_FILES := ImgFun.cpp
include $(BUILD_SHARED_LIBRARY)
在Android.mk文件中,需要主要修改的代碼是如下一行:
include D:\OpenCV-android-sdk\sdk\native\jni\OpenCV.mk
Application.mk 
APP_STL:=gnustl_static
APP_CPPFLAGS:=-frtti -fexceptions
APP_ABI := all
Reference:
http://blog.csdn.net/watkinsong/article/details/8829235
http://blog.csdn.net/watkinsong/article/details/9849973

安裝環境

No comments:

Post a Comment