参考: [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);
}
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
/* 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
根据.h的定义,编写cpp程序,程序对图片执行canny运算,留意代码中的格式转换,程序将Mat的地址作为参数,用了long到指针的强转。
#include
#include
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 ) ;
}
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
LOCAL_SRC_FILES := com_example_haveimgfun_LibImgFun.cpp
include $(BUILD_SHARED_LIBRARY)
其中,LOCAL_MODULE后面的ImgFun是最终产生的.so文件的名字,应该与LibImgFun.java中
System.loadLibrary("ImgFun");的引号中的内容一致。
APP_STL:=gnustl_static
APP_CPPFLAGS:=-frtti -fexceptions
APP_ABI:=armeabi armeabi-v7a
写好上述两个文件之后,在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
程序运行结果
点击按钮后