九层之台,起于累土;千里之堤毁于蚁穴;成者半于九十。最近工程项目完全可以调试,却最后在 OpenCV向JNI层的参数转换 这个节点上遇到麻烦,看来得好好的思考一番,仔细寻找其中的纰漏。

一、实例

根据可运行的openCv sample,可以用与人脸检测的函数是这样的:

//貌似 必须要特殊编写,便可以默认调用!wishchin!
public Mat onCameraFrame(CvCameraViewFrame inputFrame) { mRgba = inputFrame.rgba();
mGray = inputFrame.gray(); if (mAbsoluteFaceSize == 0) {
int height = mGray.rows();
if (Math.round(height * mRelativeFaceSize) > 0) {
mAbsoluteFaceSize = Math.round(height * mRelativeFaceSize);
}
mNativeDetector.setMinFaceSize(mAbsoluteFaceSize);
} MatOfRect faces = new MatOfRect(); if (mDetectorType == JAVA_DETECTOR) {
if (mJavaDetector != null)
mJavaDetector.detectMultiScale(mGray, faces, 1.1, 2, 2, // TODO: objdetect.CV_HAAR_SCALE_IMAGE
new Size(mAbsoluteFaceSize, mAbsoluteFaceSize), new Size());
}
else if (mDetectorType == NATIVE_DETECTOR) {
if (mNativeDetector != null)
mNativeDetector.detect(mGray, faces);//Detect 面部的代码,使用C++!wishchin!
}
else {
Log.e(TAG, "Detection method is not selected!");
} //0.2.把检测到的框画在图片上!wishchin!
Rect[] facesArray = faces.toArray();
for (int i = 0; i < facesArray.length; i++){
Core.rectangle(mRgba, facesArray[i].tl(), facesArray[i].br(), FACE_RECT_COLOR, 3);
}
if (mNativeDetector != null){
//Detect 使用C++!wishchin!
//mCamParam.dof6CamRecog(mGray,mCamParam);//具体函数已经转移!
}
return mRgba;
}

函数分析:

主要处理过程:

 mNativeDetector.detect(mGray, faces);//Detect 面部的代码,使用C++!wishchin!

所使用的函数:

public void detect(Mat imageGray, MatOfRect faces) {
nativeDetect( mNativeObj, imageGray.getNativeObjAddr(), faces.getNativeObjAddr() );
}

所调用的Native函数:

private static native void nativeDetect(long thiz, long inputImage, long faces);

对应CPP内的JNI接口:

JNIEXPORT void JNICALL
Java_com_example_feeljulygpsmap_FeelJulyGpsMap_nativeDetect
(JNIEnv * jenv, jclass,
jlong thiz,
jlong imageGray, jlong faces)
{
LOGD("Java_org_opencv_samples_facedetect_DetectionBasedTracker_nativeDetect enter");
try
{
vector<Rect> RectFaces;
((DetectionBasedTracker*)thiz)->process(*((Mat*)imageGray));
((DetectionBasedTracker*)thiz)->getObjects(RectFaces);
vector_Rect_to_Mat(RectFaces, *((Mat*)faces));
}
catch(cv::Exception& e)
{
LOGD("nativeCreateObject caught cv::Exception: %s", e.what());
jclass je = jenv->FindClass("org/opencv/core/CvException");
if(!je)
je = jenv->FindClass("java/lang/Exception");
jenv->ThrowNew(je, e.what());
}
catch (...)
{
LOGD("nativeDetect caught unknown exception");
jclass je = jenv->FindClass("java/lang/Exception");
jenv->ThrowNew(je, "Unknown exception in JNI code DetectionBasedTracker.nativeDetect()");
} LOGD("Java_org_opencv_samples_facedetect_DetectionBasedTracker_nativeDetect exit");
}

二、参数解析

1.java到C++

第一层参数转换:由Java到C++,通过jlong类型

转换语法:

nativeDetect( mNativeObj,
imageGray.getNativeObjAddr(), faces.getNativeObjAddr() );

通过Mat型 .getNativeObjAddr()成员函数获取矩阵地址,通过jlong型进行JNI参数代入

对应形式:

JNIEXPORT void JNICALL
Java_com_example_feeljulygpsmap_FeelJulyGpsMap_nativeDetect
(JNIEnv * jenv, jclass,
jlong thiz,
jlong imageGray, jlong faces)

函数进行运算的过程:

 ((DetectionBasedTracker*)thiz)->process(*((Mat*) imageGray) );

涉及到的第二次参数转化:

*((Mat*) imageGray) 

把jlong型在C++层强制转化为Mat类型的指针,供其他C++函数使用,由此完成Java层到C++层的全部语法转换!

其中前两个参数的作为JNI本地参数默认调用;

第三个参数jlong thiz顾名思义即是所使用参数类的载入地址,通过获取C++类的地址载入,由此可以使用在底层使用C++的类,并获取C++类的类函数和成员变量。

第四个和第五个参数分别对应了java层载入的两个mat型参数的地址,由此完成java向JNI层的陷入。

自此检测,我的代码和sample在语法层面完全一致,并且代入变元的语义一致,在此过程的移植方法上,理所应当是没有错误的。

注意事项:不管有没有声明const,载入的Mat型是不能被改变的,已经初始化的mat型不能再被修改,比如

<del>*((Mat*) imageGray)</del>

为什么?难道是为了保持上层变量的完整性?

2.由C++到java层

参数变元,经过一系列运算,得到函数结果,或者以参数或者以返回值的方式向java层返回。

由C++到java层返回的语法是这样的:

mNativeDetector.detect(mGray, faces);//Detect 面部的代码,使用C++!wishchin!

所调用的java函数:

 mNativeDetector.detect(mGray, faces);//Detect 面部的代码,使用C++!wishchin!
<pre name="code" class="java"> public void detect(Mat imageGray, MatOfRect faces) {
nativeDetect( mNativeObj, imageGray.getNativeObjAddr(), faces.getNativeObjAddr() );
}

所使用的Native函数:

private static native void nativeDetect(long thiz, long inputImage, long faces);

对应CPP内的JNI接口:

JNIEXPORT void JNICALL
Java_com_example_feeljulygpsmap_FeelJulyGpsMap_nativeDetect
(JNIEnv * jenv, jclass,
jlong thiz,
jlong imageGray, jlong faces);

JNI函数处理过程:

        ((DetectionBasedTracker*)thiz)->getObjects(RectFaces);
vector_Rect_to_Mat(RectFaces, *((Mat*)faces));

参数转变的函数调用:

vector_Rect_to_Mat(RectFaces, *((Mat*)faces));

参数转变函数:

inline void vector_Rect_to_Mat(vector<Rect>& v_rect,  Mat& mat)
{
mat = Mat(v_rect, true);
}

完成效果:

返回脸部检测的识别框,压入Vector,并通过函数强制转换成 Mat型指针

java顶层调用:

//0.2.把检测到的框画在图片上!wishchin!
Rect[] facesArray = faces.toArray();

这样可以通过数组转化为java层的 CvArray 类型,

以便

for (int i = 0; i < facesArray.length; i++){
Core.rectangle(mRgba, facesArray[i].tl(), facesArray[i].br(), FACE_RECT_COLOR, 3);
}

此代码段使用。

显示效果为:

OpenCV向JNI层的参数转换的更多相关文章

  1. Jni层回调java代码【转】

    本文转载自:http://www.linuxidc.com/Linux/2014-03/97562.htm JNI是Java Native Interface的缩写,是Java平台的重要特性,使得Ja ...

  2. 在ubuntu12.04下编译android4.1.2添加JNI层出现问题

    tiny4412学习者,在ubuntu12.04下编译android4.1.2添加JNI层出现问题: (虚心请教解决方法) trouble writing output: Too many metho ...

  3. Java层与Jni层的数组传递(转)

    源:Java层与Jni层的数组传递 Android开发中,经常会在Java代码与Jni层之间传递数组(byte[]),一个典型的应用是Java层把需要发送给客户端的数据流传递到Jni层,由Jni层的S ...

  4. Android中关于JNI 的学习(三)在JNI层訪问Java端对象

    前面两篇文章简介了JNI层跟Java层的一些相应关系,包含方法名,数据类型和方法名称等,相信在理论层面.可以非常好地帮助我们去了解JNI在Native本地开发中的作用,对JNI的一些概念也有了一个初步 ...

  5. Android 从上层到底层-----jni层

    CPU:RK3288 系统:Android 5.1 功能:上层 app 控制 led 亮灭 开发板:Firefly RK3288 led_jni.h path:hardware/rockchip/fi ...

  6. NDK,在JNI层使用AssetManager读取文件

    NDK,二进制文件数据读取,在JNI层,通过AAssetManager读取asset内部的资源: 需要头文件的支持 #include <android/asset_manager_jni.h&g ...

  7. Android开发实践:Java层与Jni层的数组传递

    转载:http://www.linuxidc.com/Linux/2014-03/97561.htm Android开发中,经常会在Java代码与Jni层之间传递数组(byte[]),一个典型的应用是 ...

  8. Android Jni层 创建 linux socket 出错问题解决

    问题: 想在Jni层创建 udp socket 与服务端通信,可是没有成功.最后发现居然是创建socket失败(代码例如以下) // create socket g_sd = socket(AF_IN ...

  9. 基于Eclipse的Android JNI层測试应用开发过程记录

    前言 本文记录一个Java层与JNI层參数与数据交互的应用程序开发过程.为实现一个功能完整的带Java与JNI的应用程序打下基础. 本文如果读者已搭建好Android的Eclipse与NDK开发环境, ...

随机推荐

  1. Flask-SQLAlchemy中解决1366报错

    会报下面这个1366的错 安装MySQL驱动(我升级过Python,所以要再装一遍) 本想安装MySQL官方驱动mysql-connector-python的,然而官方目前只支持到3.4 我又懒,所以 ...

  2. DOMContentLoaded 与onload区别以及使用

    一.何时触发这两个事件? 1.当 onload 事件触发时,页面上所有的DOM,样式表,脚本,图片,flash都已经加载完成了. 2.当 DOMContentLoaded 事件触发时,仅当DOM加载完 ...

  3. 基于JavaScript封装的Ajax工具类

    前段是件由于工作需要无奈编写了一个给予JavaScript封装的工具类,技术有限,误喷,感谢大家的支持. 1.以下是JavaScript 的 Ajax 工具类. function createXMLH ...

  4. Android第三方文件选择器:aFileChooser

     Android第三方文件选择器:aFileChooser aFileChooser是Android平台上的一个第三方文件选择器,其在github上的项目主页是:https://github.co ...

  5. Python 4 循环语句while

    while  [条件]:        条件这里满足布尔运算True则无限循环while里面代码. 固定条件的 基本的while循环, 如果if匹配那么 则执行打印登录成功,和break跳出整个循环, ...

  6. .Net操作Excel —— NPOI

    近期的两个项目都有关于NPOI的功能,经过了一点学习,自己也摸索了一会,感觉还有点意思.现在将部分代码分享一下.一部分是C#代码,一部分是VB.Net的,懒得修改了,基本上都是从项目文件中copy出来 ...

  7. redis高可用,保证高并发

    目录 redis如何通过读写分离来承载读请求QPS超过10万+ redis replication以及master持久化对主从架构的安全意义 redis主从复制原理.断点续传.无磁盘化复制.过期key ...

  8. Spring整体架构

    Spring整体架构 Spring的整体架构 Spring框架是分层架构的,它包含了一系列的功能要素. Spring整体架构图 模块分类 1. Core Container Core Containe ...

  9. JQuery获取select选中值和清除选中状态(转)

    1.获取值 var provinceSearch = $("#loc_province_search").find("option:selected").att ...

  10. zookeeper协调技术

    本文转自http://www.cnblogs.com/wuxl360/p/5817471.html 感谢作者 一.分布式协调技术 在给大家介绍ZooKeeper之前先来给大家介绍一种技术——分布式协调 ...