OpenCV向JNI层的参数转换
九层之台,起于累土;千里之堤毁于蚁穴;成者半于九十。最近工程项目完全可以调试,却最后在 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层的参数转换的更多相关文章
- Jni层回调java代码【转】
本文转载自:http://www.linuxidc.com/Linux/2014-03/97562.htm JNI是Java Native Interface的缩写,是Java平台的重要特性,使得Ja ...
- 在ubuntu12.04下编译android4.1.2添加JNI层出现问题
tiny4412学习者,在ubuntu12.04下编译android4.1.2添加JNI层出现问题: (虚心请教解决方法) trouble writing output: Too many metho ...
- Java层与Jni层的数组传递(转)
源:Java层与Jni层的数组传递 Android开发中,经常会在Java代码与Jni层之间传递数组(byte[]),一个典型的应用是Java层把需要发送给客户端的数据流传递到Jni层,由Jni层的S ...
- Android中关于JNI 的学习(三)在JNI层訪问Java端对象
前面两篇文章简介了JNI层跟Java层的一些相应关系,包含方法名,数据类型和方法名称等,相信在理论层面.可以非常好地帮助我们去了解JNI在Native本地开发中的作用,对JNI的一些概念也有了一个初步 ...
- Android 从上层到底层-----jni层
CPU:RK3288 系统:Android 5.1 功能:上层 app 控制 led 亮灭 开发板:Firefly RK3288 led_jni.h path:hardware/rockchip/fi ...
- NDK,在JNI层使用AssetManager读取文件
NDK,二进制文件数据读取,在JNI层,通过AAssetManager读取asset内部的资源: 需要头文件的支持 #include <android/asset_manager_jni.h&g ...
- Android开发实践:Java层与Jni层的数组传递
转载:http://www.linuxidc.com/Linux/2014-03/97561.htm Android开发中,经常会在Java代码与Jni层之间传递数组(byte[]),一个典型的应用是 ...
- Android Jni层 创建 linux socket 出错问题解决
问题: 想在Jni层创建 udp socket 与服务端通信,可是没有成功.最后发现居然是创建socket失败(代码例如以下) // create socket g_sd = socket(AF_IN ...
- 基于Eclipse的Android JNI层測试应用开发过程记录
前言 本文记录一个Java层与JNI层參数与数据交互的应用程序开发过程.为实现一个功能完整的带Java与JNI的应用程序打下基础. 本文如果读者已搭建好Android的Eclipse与NDK开发环境, ...
随机推荐
- hdu2001 计算两点间的距离【C++】
计算两点间的距离 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Su ...
- ActiveMQ学习总结(5)——Java消息服务JMS详解
JMS: Java消息服务(Java Message Service) JMS是用于访问企业消息系统的开发商中立的API.企业消息系统可以协助应用软件通过网络进行消息交互. JMS的编程过程很简单,概 ...
- [ZJOI2010]Perm
[ZJOI2010]Perm 题目 称一个1,2,...,N的排列P1,P2...,Pn是Magic的,当且仅当2<=i<=N时,Pi>Pi/2. 计算1,2,...N的排列中有多少 ...
- 洛谷 1373 dp 小a和uim之大逃离 良心题解
洛谷 1373 dp 这题还不算太难,,当初看的时候不是很理解题意,以为他们会选择两条不同的路径,导致整体思路混乱 传送门 其实理解题意和思路之后还是敲了不短的时间,一部分身体原因再加上中午休息不太好 ...
- 最小生成树prime算法模板
#include<stdio.h> #include<string.h> using namespace std; int map[505][505]; int v, e; i ...
- asp.net--mvc--异步编程
Using Asynchronous Methods in ASP.NET MVC 4 asp.net mvc中的异步只能增加系统的性能,原来需要500个线程的,现在需要50个就够了,对一些常规的程序 ...
- Spring MVC REST 风格的 URL
前言 本文主要内容为 REST 风格的 URL. REST REST(Representational State Transfer).(资源)表现层状态转化.它是一种架构风格,用 url 来访问网络 ...
- ZooKeeper的配置文件优化性能(转)
一.前言 ZooKeeper的功能特性通过ZooKeeper配置文件来进行控制管理( zoo.cfg配置文件). ZooKeeper这样的设计其实是有它自身的原因的.通过前面对ZooKeeper的配置 ...
- Spring MVC-集成(Integration)-集成LOG4J示例(转载实践)
以下内容翻译自:https://www.tutorialspoint.com/springmvc/springmvc_log4j.htm 说明:示例基于Spring MVC 4.1.6. 以下示例说明 ...
- 开源GIS软件 4
空间数据操作框架 Apache SIS Apache SIS 是一个空间的框架,可以更好地搜索,数据聚类,归档,或任何其他相关的空间坐标表示的需要. kvwmap kvwmap是一个采用PHP开发的W ...