2.配置环境变量$NDKROOT=android-ndk的文件夹路径
3.eclipse安装CDT插件,Eclipse->help->Install software,在"available software sites"中选择相应的CDT路径,安装
4.下载最新的OpenCV for Anroid库OpenCV-2.4.4-android-sdk.zip ,解压至本地
5.编译生成openCV的jar库文件
1)eclipse中导入OpenCV-2.4.4-android-sdk\sdk\java文件夹
2)添加openCV Library工程的C++工程属性,右键project名称->New->other->C/C++->Convert to a C/C++ Project(Adds C/C++ Nature)
3)为project 配置ndk built路径。右键project->Properties->C/C++ build, 设置Build command: ${NDKROOT}/ndk-build.cmdbehavior选项中的不勾clean
4)编译工程, /bin文件夹下生成opencv library - 2.4.4.jar
6. 在目标Adnroid应用程序中添加对opencv library - 2.4.4.jar 的引用,便可以调用相应的open CV库函数了
在Android中使用Opencv使用opencv有两种方式,一种是使用opencv的java版本的API,但是这种方式不是通过本地调用实现的,全部都是java代码,所以这里先不讲,另外一种方式就是使用opencv的c++版本的API,将本地c++代码编译成.so链接库,然后在安卓开发中进行调用,本地cpp代码使用NDK进行编译。
5.1
安卓代码
下面给出一个使用Canny算子检测边缘的本地代码调用的使用方式。
新建安卓项目,配置使用安卓API等信息,这里我的项目名称为HaveImgFun
然后修改界面控制文件res->layout->activity_have_img_fun.xml
<?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="还原" />
<ImageView android:id="@+id/ImageView01"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</LinearLayout>
在文件夹src下的com.testopencv.haveimgfun包中新建一个类用于包装使用了opencv
c++代码的动态库的导出函数,类名为LibImgFun。
Eclipse会为你创建一个新的文件LibImgFun.java,将里面的内容改为:
package com.testopencv.haveimgfun
public class LibImgFun {
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)
}
从上面的代码可以得知,我们的动态库名字应该为“libImgFun.so”,注意"public
static native int[] ImgFun(int[] buf, int w, int h)"中的native关键字,表明这个函数来自native
code。static表示这是一个静态函数,这样就可以直接用类名去调用。
修改功能代码,修改HaveImgFun.java的代码,代码内容如下:
package com.testopencv.haveimgfun
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 HaveImgFun extends Activity {
/** Called when the activity is first created. */
ImageView imgView
Button btnNDK, btnRestore
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_have_img_fun)
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)
HaveImgFun.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)
HaveImgFun.this.setTitle("使用OpenCV进行图像处理")
}
}
}
}
5.2 C++代码
在项目中新建一个jni文件,用于放置该项目的所有cpp代码。
在jni文件夹下建立一个"ImgFun.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_testopencv_haveimgfun_LibImgFun_ImgFun(
JNIEnv* env, jobject obj, jintArray buf, int w, int h)
JNIEXPORT jintArray JNICALL Java_com_testopencv_haveimgfun_LibImgFun_ImgFun(
JNIEnv* env, jobject obj, jintArray buf, int w, int h) {
jint *cbuf
cbuf = env->GetIntArrayElements(buf, false)
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=0i<w*hi++)
{
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 = 0row <src->heightrow++) {
for (int col = 0col <src->widthcol++) {
CvScalar s = cvGet2D(src, row, col)
cvSet2D(destImg, row, col, s)
}
}
return destImg
}
在上面的代码中,给出了简单的Canny算子检测边缘的代码,并且返回检测后的图像显示。
上面的代码中#include
<jni.h>是必须要包含的头文件,#include
<opencv2/opencv.hpp>是opencv要包含的头文件。
5.3
配置文件
然后再在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 E:\java\OpenCV-2.4.5-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)
Application.mk: APP_STL:=gnustl_static
APP_CPPFLAGS:=-frtti -fexceptions
APP_ABI:=armeabi armeabi-v7a
在Android.mk文件中,需要主要修改的代码是如下一行: include E:\java\OpenCV-2.4.5-android-sdk\sdk\native\jni\OpenCV.mk
这里需要将Android
SDK中的OpenCV.mk文件包含进来,可以使用相对路径或者绝对路径。但是最好不要将Android
SDK放在和工作空间不在一个磁盘分区的地方,这样很容易出错。
然后需要使用LOCAL_SRC_FILES包含需要编译的文件。
5.4
编译本地C++代码
编译本地C++代码可以使用Cygwin进行编译,cd
到项目目录,然后运行ndk-build
也可以使用windows控制台进行编译,同样cd到项目目录,运行ndk-build
还可以使用Eclipse进行编译,建议配置使用Eclipse进行编译,这样当项目的本地cpp代码发生变化的时候就可以实现自动的cpp代码编译,不用每次都在命令行中手动的进行编译,虽然使用黑乎乎的命令行手动编译,输出一堆信息显着很牛逼的样子。
(一下内容,如果使用cygwin进行编译,则不需要进行 *** 作,直接使用cygwin或者命令行进行编译,保证编译通过以后即可运行程序,如果选择使用Eclipse自动进行编译,则参考一下内容进行配置)
首先需要将该项目转换到C++项目,使得该项目具有C++代码属性,如下所述。
点击项目,右击,
New
->Other ->C/C++ ->Convert to a C/C++ Project .
配置Eclipse对cpp代码进行编译:
首先需要给当前项目添加一个编译环境变量
如下目录
open
Eclipse menu Window ->Preferences ->C/C++ ->Build
->Environment ,
点击
Add...
添加一个NDKROOT,并且设置值为Android
SDK的根目录。
然后设置编译的一些参数
Project
Properties ->C/C++ Build , uncheck Use
default build command ,
replace “Build command” text from "make"
to
"${NDKROOT}/ndk-build.cmd"
on Windows,
"${NDKROOT}/ndk-build"
on Linux and MacOS.
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)