九层之台,起于累土;千里之堤毁于蚁穴;成者半于九十。最近工程项目完全可以调试,却最后在 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. 洛谷P1055 ISBN号码【字符数组处理】

    题目描述 每一本正式出版的图书都有一个ISBN号码与之对应,ISBN码包括 99 位数字. 11 位识别码和 33 位分隔符,其规定格式如x-xxx-xxxxx-x,其中符号-就是分隔符(键盘上的减号 ...

  2. 【Codeforces 349B】Color the Fence

    [链接] 我是链接,点我呀:) [题意] 让你组成一个只由1~9组成的数字 每个数字需要的paint数字给定. 让你组成一个最大的数字,且所有数字的paint的总和不超过v. [题解] 先求出a中的最 ...

  3. ReportNG 替换testng获得测试报告

    1.导入reportng相关jar包

  4. F - Many Moves

    F - Many Moves Time limit : 2sec / Memory limit : 256MB Score : 900 points Problem Statement There a ...

  5. [bzoj3450]Tyvj1952 Easy[概率dp]

    和之前一样考虑这个音符时x还是o,如果是x,是否是新的连续一段,对答案的贡献是多少$(a^2-{(a-1)}^2)$,然后递推就可以了. #include <bits/stdc++.h> ...

  6. hdu_1012_u Calculate e_201310121519

    u Calculate eTime Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Tota ...

  7. spring历史背景

    1.2004年spring出现第一版本spring frameworl1.0 2.写代码永远是最简单的,后续的运维工作才是让人感到无助的 3.spring boot在运维方面做了很多工作,部署,监控, ...

  8. HDU 4542

    T_T终于让我过了,坑啊,竟然时限是200ms... 我是预处理出不整除了个数的,因为这个较容易一点.利用算术基本定理,f=p1^a1*p2^a2...... 所以,整除它的个数就是(a1+1)*(a ...

  9. CSUOJ 1329 一行盒子(数组模拟链表)

    题目:id=1329">http://acm.csu.edu.cn/OnlineJudge/problem.php? id=1329 题意: watermark/2/text/aHR0 ...

  10. SQL 用户定义表类型,在存储过程里使用数据类型作參数

    在数据库编程里使用数据类型,能够提高代码的重用性.它们常常被使用在方法和存储过程中.使用数据类型,我们能够避免在存储过程里定义一串的參数,让人眼花缭乱,它就相当于面向对象语言里.向一个方法里传入一个对 ...