您的位置:首页 > 编程语言 > C语言/C++

Android调用C++OpenCV程序的方法(NDK+JNI)

2015-08-03 21:06 726 查看
参考: [1] http://blog.csdn.net/donglynn/article/details/23046925

[2]http://www.cnblogs.com/devinzhang/archive/2012/02/29/2373729.html

[3]http://www.tuicool.com/articles/yaeeuu

[4]《细说Android4.0 NDK编程》

1.环境搭建

Android 环境搭建

OpenCV4Android安装

安装CDT

安装Android NDK

安装Cygwin

上述安装过程可参考[2]

2.创建Java类,用于加载本地C++文件,声明本地的C++方法

创建Android工程,载入Opencv4Android库。

新建Java类,名为LibImgFun.

package com.example.haveimgfun;

public class LibImgFun {
	static{
                //加载本地C++库文件
		System.loadLibrary("ImgFun");
	}

        //声明本地方法
	public native void canny(long matAddrInRGBA, long matAddroutInRGBA);
}


编写完成后,eclipse会自动编译,在工程\bin\classes\com\example\haveimgfun下产生LibImgFun.class.

3.使用javah工具产生C语言的.h头文件

打开Windows 命令行,进入工程\bin\classes,执行命令javah com.example.haveimgfun.LibImgFun

执行完成后,在工程\bin\classes文件夹下产生com_example_haveimgfun_LibImgFun.h文件,在工程目录下新建jni文件夹,将.h文件移到jni文件夹中。

下面是.h文件的内容

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_haveimgfun_LibImgFun */

#ifndef _Included_com_example_haveimgfun_LibImgFun
#define _Included_com_example_haveimgfun_LibImgFun
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_example_haveimgfun_LibImgFun
 * Method:    processImg
 * Signature: (JJ)V
 */
JNIEXPORT void JNICALL Java_com_example_haveimgfun_LibImgFun_canny
  (JNIEnv *, jobject, jlong, jlong);

#ifdef __cplusplus
}
#endif
#endif


4.编写cpp程序

根据.h的定义,编写cpp程序,程序对图片执行canny运算,留意代码中的格式转换,程序将Mat的地址作为参数,用了long到指针的强转。

#include <com_example_haveimgfun_LibImgFun.h>
#include <opencv2/opencv.hpp>
 
JNIEXPORT void JNICALL Java_com_example_haveimgfun_LibImgFun_canny
   ( JNIEnv * , jobject , jlong addrInRGBA , jlong addrOut ) {
     cv :: Mat * pMatInRGBA = ( cv :: Mat * ) addrInRGBA ;
     cv :: Mat * pMatOut = ( cv :: Mat * ) addrOut ;
     cv :: Mat imageGray ;
     cv :: cvtColor ( * pMatInRGBA , imageGray , CV_RGBA2GRAY ) ;
     cv :: Canny ( imageGray , * pMatOut , 30 , 90 ) ;
}


5.编写Android.mk和Application.mk作为ndk-build的makefile
Android.mk和Application.mk可以在ndk安装目录\samples\hello-jni\jni文件夹中找到,复制到工程\jni中。

Android.mk:

# Copyright (C) 2009 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0 #
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

include D:/OpenCV-2.4.9-android-sdk/sdk/native/jni/OpenCV.mk

LOCAL_MODULE    := ImgFun<span style="white-space:pre">		</span>
LOCAL_SRC_FILES := com_example_haveimgfun_LibImgFun.cpp

include $(BUILD_SHARED_LIBRARY)
其中,LOCAL_MODULE后面的ImgFun是最终产生的.so文件的名字,应该与LibImgFun.java中System.loadLibrary("ImgFun");的引号中的内容一致。

Application.mk:

APP_STL:=gnustl_static  
APP_CPPFLAGS:=-frtti -fexceptions  
APP_ABI:=armeabi armeabi-v7a


6.编译cpp程序

写好上述两个文件之后,在jni/目录下执行 <mdk_path>/ndk-build (将 <ndk_path> 改为ndk的安装路径)。顺利的话,可以看到输出信息最后一行:

1

[ armeabi - v7a ] Install : libprocess_frame . so = > libs / armeabi - v7a /libprocess_frame . so

说明已经编译成功了。

7.编写MainActivity,执行程序

package com.example.haveimgfun;

import org.opencv.android.BaseLoaderCallback;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;

//opencv
import org.opencv.android.BaseLoaderCallback;  
import org.opencv.android.LoaderCallbackInterface;  
import org.opencv.android.OpenCVLoader;  
import org.opencv.android.Utils;  
import org.opencv.core.Mat;  
import org.opencv.imgproc.Imgproc;  

import com.example.haveimgfun.R;

public class MainActivity extends Activity {
	
	private Button button;
	private ImageView image; 
	private Bitmap bmp;
	private TextView text;
	
	//Opencv加载
	
	private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this){
		@Override
		public void onManagerConnected(int status) {
			switch (status) {  
				case LoaderCallbackInterface.SUCCESS:{ 
					System.out.println("load opencv sucess");
				} break;  
				default:{  
					super.onManagerConnected(status);  
				} break;  
			}  
		}
	};
			
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		image = (ImageView)findViewById(R.id.ImageView);
		button = (Button)findViewById(R.id.button);
		text = (TextView)findViewById(R.id.text);
		
		ButtonListener buttonListener = new ButtonListener();
		button.setOnClickListener(buttonListener);
		//graph
		bmp = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
		image.setImageBitmap(bmp);
		text.setText("code ok!");
	}

	class ButtonListener implements OnClickListener{

		@Override
		public void onClick(View v) {
			text.setText("button is pressed!");
			Mat rgbMat = new Mat();
			Mat resultMat = new Mat();
			Utils.bitmapToMat(bmp, rgbMat); 
			
			text.setText("row: "+rgbMat.rows()+" col:"+rgbMat.cols()+" channels: "+rgbMat.channels());
			
			//load c++
			LibImgFun libimagefun = new LibImgFun();
			
			libimagefun.canny(rgbMat.getNativeObjAddr(),resultMat.getNativeObjAddr());
			
			text.setText("canny OK!");
			Utils.matToBitmap(resultMat, bmp); 
            image.setImageBitmap(bmp);  
		}
	}
	
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}
	
	@Override
	public void onResume(){
		super.onResume();
		OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_9, this, mLoaderCallback);
	}

}


activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <TextView
        android:id="@+id/text"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="hello" />
    
    <Button
        android:id="@+id/button"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="使用C++OpenCV处理图像" />
    
    <ImageView
        android:id="@+id/ImageView"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />
    
    

</LinearLayout>


程序运行结果



点击按钮后

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: