您的位置:首页 > 移动开发 > Android开发

NDK使用 ,OpenCV库的调用,在NDK中使用纯C++代码,android studio 2.1(1)

2016-07-25 19:11 288 查看

NDK使用 ,OpenCV库的调用,在NDK中调用纯C++代码,android studio 2.1(1)

盖天地不全,这经原是全全的,今沾破了, 乃是应不全之奥妙也,岂人力 所能与耶! 愿来者补充

最近需要把一个使用了OpenCV(249)的C++人脸检测的代码,转到Android中使用,恰好Android Studio2.1可以使用NDK这么一个很好用的东西来直接代码。故,决定使用NDK,但是这个里面的坑确实太多了,决定写下来,提醒自己也帮助他人。

1,NDK的安装,和配置OpenCV

开始的时候是借鉴这篇文章[Android开发配置opencv环境超详细教程

这篇文章确实很详细,但是我在运行的时候还有遇到了一些小麻烦,

:1下载NDK和OpenCV for android

选择你的项目,右键



可以选择download 或者选择解压自己的下载的NDK的路径



你就可以看到local.properite文件中就添加了NDK路径



:2 添加opencv native包,这个是为了C++代码中需要使用到OpenCV的库。

方法呢更最前面说的文章做法一样我就不再过多说明了

我就说明一点,下载的是OpenCV-**-Android-sdk这样的,然后解压就可以了。

:3,编辑gradle.properties文件

在文件最后一行直接添加android.useDeprecatedNdk=true ,这句好,这句话我之前没有添加,老是报错说要添加,后来查了一下是因为增加下面的属性使用旧版的ndk功能(不添加会使用实验性的ndk构建工具)

:4,接下来几步,和最前面说的文章做法一样

但我安装他的安装步骤就是运行不了,就是会出错,后来发现好像是他的代码中出现了一下问题。这里没有说他错的意思,可能是版本不同,或者配置不一样,才导致最后我运行失败了。

#include "com_example_administrator_tryopencv_OpenCVHelper.h"
#include <stdio.h>
#include <stdlib.h>
#include <opencv2/opencv.hpp>

using namespace cv;

extern "C" {

/*注意这里,下面2行,这里,我使用的时候是直接拷贝他的,但是运行就出现找不到这个方法,错误
然后我就有点发现者2行代码是多余的吗,我就删除了者下面2行结果就对了*/
JNIEXPORT jintArray JNICALL Java_com_example_administrator_tryopencv_OpenCVHelper_gray(JNIEnv *env,jclass obj,jintArray buf,int w,int h);

JNIEXPORT jintArray JNICALL Java_com_example_administrator_tryopencv_OpenCVHelper_gray(JNIEnv *env,jclass obj,jintArray buf,int w,int h)
{
jint *cbuf;
cbuf = env->GetIntArrayElements(buf,JNI_FALSE);
if (NULL == cbuf)
{
return 0;
}

Mat imgData(h,w,CV_8UC4,(unsigned char*) cbuf);

u_char *ptr = imgData.ptr(0);
for (int i = 0; i < w*h; ++i)
{
//图像存储方式为:BGRA
int grayScale = (
b3e6
int)(ptr[4*i+2]*0.299 + ptr[4*i+1]*0.587 + ptr[4*i+0]*0.144 );
ptr[4*i+0] = grayScale;
ptr[4*i+1] = grayScale;
ptr[4*i+2] = grayScale;
}

int size = w * h;
jintArray  result = env->NewIntArray(size);
env->SetIntArrayRegion(result,0,size,cbuf);
env->ReleaseIntArrayElements(buf,cbuf,0);
return result;
}

}


:5到这里NDK的安装和OpenCV的添加调用,基本都没有问题,

2,怎么调用纯C++代码呢,或者说以前自己写的C++代码呢?

要是都按照上面的方法来写C++代码的话就太麻烦了,这也不是google的风格,肯定有个方法可以直接调用C++的代码。但是我查了好多,看了其他人写的博客,实在是找不到,办法。。最后只能去求助官方给的文档和代码。哈哈,,虽然麻烦了一点,但是结果是好的。下面来说一下

我先看了一下文档觉得不行,然后只能求助代码官方给的一些实例然后我就找到了其中naticve-codec/jin这里下面的代码,看到looper.h文件就是纯C的我就知道有希望了,然后查看了Android.mk文件,看下面

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := native-codec-jni
/*重点在这里,看到没有,loop.cpps是C++的代码,这么写就可以直接调用而不会出现没有这个文件,或者没有编译的情况,是不是很简单,但是我查了很多,都没有找到要不就是"./looper.cpp"这样的,我要来解释一下,对于纯C++代码,是“空格+文件名.cpp”这样添加的,而自己写的作为java和c++代码的交接的地方就是包含这样函数“JNIEXPORT jintArray JNICALL Java_com_example_administrator_gray”的代码文件是“./+文件名.cpp”,形式的*/
LOCAL_SRC_FILES := native-codec-jni.cpp looper.cpp
# for native multimedia
LOCAL_LDLIBS    += -lOpenMAXAL -lmediandk
# for logging
LOCAL_LDLIBS    += -llog
# for native windows
LOCAL_LDLIBS    += -landroid

LOCAL_CFLAGS    += -UNDEBUG

include $(BUILD_SHARED_LIBRARY)


好了,到这里,基本可以做到,调用纯的C++代码没有问题了

3:怎么在C++代码中使用Log.e(“”,”“),这样的输出

我也看了好多介绍,说是修改Android.mk或者其他的就可以使用,我也忘了。但是我发现了一个更为简单的使用办法,这个也是在官方代码中找到的

#include <android/log.h>
#define TAG "NativeCodec-looper"//这是Log.v(TAG,"")中的TAG,自己修改就好了
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__)


在前面加上这样几句话就可以在C++代码中使用下面形式的输出,下面输出相当于Log.v

LOGV("Looper deleted while still running. Some messages will not be processed")


是不是很简单

4:对于在native方法参数中使用Bitmap或者其他类型,我只想说,方法有。但是我尝试了好多,效果并不好,那怎么办呢?我是使用byte,int这样的数据,将bitmap转为byte,然后用int等来记录长,宽就可以了。这样传就一定不会出现问题。其他类型我的建议是转为最简单的类型,这样就可以保证正确,希望以后能够支持更多类型吧

5:虽然过程很艰难,结果只需要修改几行代码,带但是我还是很开心,因为没有现成的答案,我靠自己解决了问题。后面会继续写代码,后续也会继续更新分享。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: