Android JNI 开发 Demo by NDK (native develop kit)
最近终于有了一些空闲时间,所以想着把之前的Android相关的项目整理一下,前几天整理了Android OCR 的项目, 今天就干脆再整理一下 NDK JNI调用。
关于Android 中通过JNI进行本地调用的配置与开发,已经在链接 http://blog.csdn.net/watkinsong/article/details/9849973 中给出了非常详细的说明。 请仔细阅读。
同时,关于Android 作OCR的说明,也已经 在 http://blog.csdn.net/watkinsong/article/details/45541215 给出了详细的解释。 所以,本文章不再赘述如何配置开发环境,如何创建项目等,而是直接给出一个项目,列出需要注意的几点要点。
1. 首先,通过https://github.com/weixsong/libra 链接下载该项目,找到NDKDemo项目。
2. 通过Eclipse导入项目。
3. 在调用JNI之前,我们需要定义一个接口,实现和JNI通讯,本例的接口定义:
package com.example.ndk; public class CannyDetect { static { System.loadLibrary("native"); } /** * @param width * the current view width * @param height * the current view height */ public static native int[] cannyDetect(int[] buf, int w, int h); }
接口中,要通过静态初始化代码块加载.so文件,不需要添加后缀名。 然后定义static native 的接口,这个接口需要符合JNI的规范。
4. 既然有了JNI调用接口,就要看看如何编写JNI程序:
在native.cpp 中:
#include <jni.h> #include <stdio.h> #include <stdlib.h> #include <opencv2/opencv.hpp> using namespace cv; IplImage * change4channelTo3InIplImage(IplImage * src); extern "C" { JNIEXPORT jintArray JNICALL Java_com_example_ndk_CannyDetect_cannyDetect( JNIEnv* env, jobject obj, jintArray buf, int w, int h); JNIEXPORT jintArray JNICALL Java_com_example_ndk_CannyDetect_cannyDetect( JNIEnv* env, jobject obj, jintArray buf, int w, int h) { jint *cbuf; cbuf = env->GetIntArrayElements(buf, 0); 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找不到函数阿神码神码的,麻烦您先彻底看清楚博客怎么写的。。。
这里再强调一下:
JNIEXPORT jintArray JNICALL Java_com_example_ndk_CannyDetect_cannyDetect (***)
这个函数的声明,一定要遵循JNI的标准规范,首先是
JNIEXPORT jintArray JNICALL
然后, Java_ + 包名称,其中,包中的点用_代替,然后,步骤3中定义的接口的类名,然后是方法名。
5. 注意一下Android.mk文件:
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) OPENCV_LIB_TYPE:=STATIC OPENCV_INSTALL_MODULES:=on OPENCV_CAMERA_MODULES:=off ifeq ("$(wildcard $(OPENCV_MK_PATH))","") #try to load OpenCV.mk from default install location include /home/wesong/software/OpenCV-2.4.10-android-sdk/sdk/native/jni/OpenCV.mk else include $(OPENCV_MK_PATH) endif LOCAL_MODULE := native LOCAL_SRC_FILES := native.cpp LOCAL_LDLIBS += -llog -ldl include $(BUILD_SHARED_LIBRARY)
修改里面的OpenCV.mk的路径。
6. 看一眼 Application.mk
APP_STL:=gnustl_static APP_CPPFLAGS:=-frtti -fexceptions APP_ABI:=armeabi armeabi-v7a APP_PLATFORM := android-19
7. 主程序:
package com.example.ndk; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.graphics.drawable.BitmapDrawable; import android.os.Bundle; import android.widget.Button; import android.view.View; import android.widget.ImageView; public class MainActivity extends Activity { ImageView imgView; Button btnNDK, btnRestore; private String title = "Canny detect by NDK"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); this.setTitle(title); btnRestore = (Button) this.findViewById(R.id.btnRestore); btnRestore.setOnClickListener(new ClickEvent()); btnNDK = (Button) this.findViewById(R.id.btnNDK); btnNDK.setOnClickListener(new ClickEvent()); imgView = (ImageView) this.findViewById(R.id.ImageView01); Bitmap img = ((BitmapDrawable) getResources().getDrawable( R.drawable.lena)).getBitmap(); imgView.setImageBitmap(img); } class ClickEvent implements View.OnClickListener { public void onClick(View v) { if (v == btnNDK) { long current = System.currentTimeMillis(); Bitmap img1 = ((BitmapDrawable) getResources().getDrawable( R.drawable.lena)).getBitmap(); int w = img1.getWidth(), h = img1.getHeight(); int[] pix = new int[w * h]; img1.getPixels(pix, 0, w, 0, 0, w, h); int[] resultInt = CannyDetect.cannyDetect(pix, w, h); Bitmap resultImg = Bitmap.createBitmap(w, h, Config.RGB_565); resultImg.setPixels(resultInt, 0, w, 0, 0, w, h); long performance = System.currentTimeMillis() - current; imgView.setImageBitmap(resultImg); MainActivity.this.setTitle("NDK consumed: " + String.valueOf(performance) + " ms"); } else if (v == btnRestore) { Bitmap img2 = ((BitmapDrawable) getResources().getDrawable( R.drawable.lena)).getBitmap(); imgView.setImageBitmap(img2); MainActivity.this.setTitle("使用OpenCV进行图像处理"); } } } }
截图:
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。