如何在android studio上加入OpenCV库

如何在android studio上加入OpenCV库,第1张

1.安装 NDK, 下载android-ndk-r8e-windows-x86.zip, 解压至本地(android-ndk-r8e-windows-x86_64.zip解压后不包含prebuilt文件夹,sample中的hello-jni运行报错)

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.


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/bake/11938654.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-19
下一篇 2023-05-19

发表评论

登录后才能评论

评论列表(0条)

保存