上一篇写Android+OPNECV+JNI开发模式之边缘检测的程序代码,但没有把相关的软件环境配置交代清楚,这里补上。
开发环境及软件: Windows 7 64 adt-bundle-windows-x86_64,这里面包含了eclipseV10 和SDK 与SDK manager android-ndk-r10d OpenCV-2.4.10-android-sdk 至于为什么要学习 Android下OPENCV 的NDK 开发模式,那时因为以前的很多的算法都是基于OPENCV 的C/C++写的,如果要将这些代码全部转换为JAVA这将给开发人员很大的工作量,何况前人留下了那么多的开源项目代码,放在现成的代码不用真是有点浪费。另外C/C++也有它在底层的执行效率高的特殊优势,方便对原始数据的处理。而且由于Linux系统的权限限制和Android封装架构限制,很多涉及底层设备、接口、驱动控制的应用开发,不得不使用到本文的NDK开发环境(基于Android源码或内核源码修改),开发语言使用C/C++,NDK开发更接近于Linux开发,需要更多关于Linux应用编程知识。基于以上的种种原因,在Android的环境下学习NDK的开发模式是很有必要的。 有了NDK的这种开发模式,其实你关注的更多的算法的实现,JAVA语音只要会一点点就可以开发,将开发的好的算法生成.SO的库给Android的上层应用开发人员调用就是,本人就是这么做的(无奈JAVA我也只会一点点)。 需要的软件可以到这来下载:http://pan.baidu.com/s/1i3rDdlj 按照自己的版本下载adt和ndk,一般人都有了adt,需要重点下载一下ndk解压好,任意目录。我演示的环境是64位 windows平台(adt-bundle-windows-x86_64-20140702和android-ndk32-r10-windows-x86_64)最新版下载也可以官网下载,不过好像需要翻墙。 软件如下:
下载下来的android-ndk32-r10我解压到D:盘如下图:
设置系统的环境变量:
仅此而已!! 可以开始开发了…………………… 在eclipse中新建一个Android的应用工程:
由于我已经建了一个相同名称的应用,所以会提示这个项目已经在你的workspace中了,如果你没有建过自然就不会提示了,接下来就是一路next到生成结束,我就不一一截图了。
建好工程后鼠标右键工程名给这个工程新建一个名称为jni的文件夹如图:
现在我建好的工程结构如图:
- MainActivity.java中的代码如下:
- package com.example.hellojnitest;
- import android.app.Activity;
- import android.os.Bundle;
- import android.graphics.Bitmap;
- import android.graphics.Bitmap.Config;
- import android.graphics.drawable.BitmapDrawable;
- import android.widget.Button;
- import android.view.View;
- import android.widget.ImageView;
- public class MainActivity extends Activity {
- /** Called when the activity is first created. */
- ImageView imgView;
- Button btnNDK, btnRestore;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- ////////////////////////////////////////////////////
- this.setTitle("使用NDK转换成轮廓图");
- 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 = LibImgFun.ImgFun(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("w:" + String.valueOf(img1.getWidth())
- + ",h:" + String.valueOf(img1.getHeight()) + "NDK耗时"
- + String.valueOf(performance) + " 毫秒");
- } else if (v == btnRestore) {
- Bitmap img2 = ((BitmapDrawable) getResources().getDrawable(
- R.drawable.lena)).getBitmap();
- imgView.setImageBitmap(img2);
- MainActivity.this.setTitle("使用OpenCV进行图像处理");
- }
- }
- }
- }
复制代码读者可能会问我:“为什么我的工程目录下没有LigImgeFun.java这个文件呢?”别急,这个需要自己新建。 步奏如下图:
由于我已经建过一样的每次的类库了,所以提示这个类已经在里面了,在此跳过。
LigImgeFun.java文件中的代码如下,这个类的的主要作用就是装载native的ImgFun.so库,并且提供提供函数接口: package com.example.hellojnitest; public classLibImgFun { static { System.loadLibrary("ImgFun"); } /** * @param width the current view width * @param height the current view height */ public static native int[] ImgFun(int[] buf, int w, int h); } 在jni文件夹中新建hello-jni.cpp文件,添加代码如下,这些代码就是我们熟悉的C\C++代码,只是在函数的名称上有点特别,这个以后再论: - #include <jni.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <highgui.h>
- #include <opencv2/opencv.hpp>
- using namespace cv;
- IplImage * change4channelTo3InIplImage(IplImage * src);
- extern "C" {
- JNIEXPORT
- jintArray JNICALL Java_com_example_hellojnitest_LibImgFun_ImgFun(JNIEnv* env, jobject obj, jintArray buf, int w, int h);
- JNIEXPORT
- jintArray JNICALL Java_com_example_hellojnitest_LibImgFun_ImgFun(JNIEnv* env, jobject obj, jintArray buf, int w, int h)
- {
- jint *cbuf;
- cbuf = env->GetIntArrayElements(buf, NULL);
- 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文件,这个如果开发过linux的应该很熟悉,这个是C\C++的编译配置文件,代码如下: - 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 E:\Workspace\OpenCV-2.4.10-android-sdk\sdk\native\jni\OpenCV.mk
- else
- include $(OPENCV_MK_PATH)
- endif
- LOCAL_MODULE := ImgFun
- LOCAL_SRC_FILES := hello-jni.cpp
- include $(BUILD_SHARED_LIBRARY)
复制代码在jni中新建Application.mk文件,这里面的代码主要的主要的作用是生成不同的处理器平台的工程代码,每种处理器都会产生相应的.SO库文件,代码如下: - APP_STL:=gnustl_static
- APP_CPPFLAGS:=-frtti -fexceptions
- APP_ABI:=armeabi armeabi-v7a
- APP_PLATFORM := android-19
复制代码 |