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

一、实例

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

  1. //貌似 必须要特殊编写,便可以默认调用!wishchin!
  2. public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
  3.  
  4. mRgba = inputFrame.rgba();
  5. mGray = inputFrame.gray();
  6.  
  7. if (mAbsoluteFaceSize == 0) {
  8. int height = mGray.rows();
  9. if (Math.round(height * mRelativeFaceSize) > 0) {
  10. mAbsoluteFaceSize = Math.round(height * mRelativeFaceSize);
  11. }
  12. mNativeDetector.setMinFaceSize(mAbsoluteFaceSize);
  13. }
  14.  
  15. MatOfRect faces = new MatOfRect();
  16.  
  17. if (mDetectorType == JAVA_DETECTOR) {
  18. if (mJavaDetector != null)
  19. mJavaDetector.detectMultiScale(mGray, faces, 1.1, 2, 2, // TODO: objdetect.CV_HAAR_SCALE_IMAGE
  20. new Size(mAbsoluteFaceSize, mAbsoluteFaceSize), new Size());
  21. }
  22. else if (mDetectorType == NATIVE_DETECTOR) {
  23. if (mNativeDetector != null)
  24. mNativeDetector.detect(mGray, faces);//Detect 面部的代码,使用C++!wishchin!
  25. }
  26. else {
  27. Log.e(TAG, "Detection method is not selected!");
  28. }
  29.  
  30. //0.2.把检测到的框画在图片上!wishchin!
  31. Rect[] facesArray = faces.toArray();
  32. for (int i = 0; i < facesArray.length; i++){
  33. Core.rectangle(mRgba, facesArray[i].tl(), facesArray[i].br(), FACE_RECT_COLOR, 3);
  34. }
  35. if (mNativeDetector != null){
  36. //Detect 使用C++!wishchin!
  37. //mCamParam.dof6CamRecog(mGray,mCamParam);//具体函数已经转移!
  38. }
  39. return mRgba;
  40. }

函数分析:

主要处理过程:

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

所使用的函数:

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

所调用的Native函数:

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

对应CPP内的JNI接口:

  1. JNIEXPORT void JNICALL
  2. Java_com_example_feeljulygpsmap_FeelJulyGpsMap_nativeDetect
  3. (JNIEnv * jenv, jclass,
  4. jlong thiz,
  5. jlong imageGray, jlong faces)
  6. {
  7. LOGD("Java_org_opencv_samples_facedetect_DetectionBasedTracker_nativeDetect enter");
  8. try
  9. {
  10. vector<Rect> RectFaces;
  11. ((DetectionBasedTracker*)thiz)->process(*((Mat*)imageGray));
  12. ((DetectionBasedTracker*)thiz)->getObjects(RectFaces);
  13. vector_Rect_to_Mat(RectFaces, *((Mat*)faces));
  14. }
  15. catch(cv::Exception& e)
  16. {
  17. LOGD("nativeCreateObject caught cv::Exception: %s", e.what());
  18. jclass je = jenv->FindClass("org/opencv/core/CvException");
  19. if(!je)
  20. je = jenv->FindClass("java/lang/Exception");
  21. jenv->ThrowNew(je, e.what());
  22. }
  23. catch (...)
  24. {
  25. LOGD("nativeDetect caught unknown exception");
  26. jclass je = jenv->FindClass("java/lang/Exception");
  27. jenv->ThrowNew(je, "Unknown exception in JNI code DetectionBasedTracker.nativeDetect()");
  28. }
  29.  
  30. LOGD("Java_org_opencv_samples_facedetect_DetectionBasedTracker_nativeDetect exit");
  31. }

二、参数解析

1.java到C++

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

转换语法:

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

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

对应形式:

  1. JNIEXPORT void JNICALL
  2. Java_com_example_feeljulygpsmap_FeelJulyGpsMap_nativeDetect
  3. (JNIEnv * jenv, jclass,
  4. jlong thiz,
  5. jlong imageGray, jlong faces)

函数进行运算的过程:

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

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

  1. *((Mat*) imageGray)

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

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

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

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

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

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

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

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

2.由C++到java层

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

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

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

所调用的java函数:

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

所使用的Native函数:

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

对应CPP内的JNI接口:

  1. JNIEXPORT void JNICALL
  2. Java_com_example_feeljulygpsmap_FeelJulyGpsMap_nativeDetect
  3. (JNIEnv * jenv, jclass,
  4. jlong thiz,
  5. jlong imageGray, jlong faces);

JNI函数处理过程:

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

参数转变的函数调用:

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

参数转变函数:

  1. inline void vector_Rect_to_Mat(vector<Rect>& v_rect, Mat& mat)
  2. {
  3. mat = Mat(v_rect, true);
  4. }

完成效果:

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

java顶层调用:

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

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

以便

  1. for (int i = 0; i < facesArray.length; i++){
  2. Core.rectangle(mRgba, facesArray[i].tl(), facesArray[i].br(), FACE_RECT_COLOR, 3);
  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. hdu2001 计算两点间的距离【C++】

    计算两点间的距离 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Su ...

  2. ActiveMQ学习总结(5)——Java消息服务JMS详解

    JMS: Java消息服务(Java Message Service) JMS是用于访问企业消息系统的开发商中立的API.企业消息系统可以协助应用软件通过网络进行消息交互. JMS的编程过程很简单,概 ...

  3. [ZJOI2010]Perm

    [ZJOI2010]Perm 题目 称一个1,2,...,N的排列P1,P2...,Pn是Magic的,当且仅当2<=i<=N时,Pi>Pi/2. 计算1,2,...N的排列中有多少 ...

  4. 洛谷 1373 dp 小a和uim之大逃离 良心题解

    洛谷 1373 dp 这题还不算太难,,当初看的时候不是很理解题意,以为他们会选择两条不同的路径,导致整体思路混乱 传送门 其实理解题意和思路之后还是敲了不短的时间,一部分身体原因再加上中午休息不太好 ...

  5. 最小生成树prime算法模板

    #include<stdio.h> #include<string.h> using namespace std; int map[505][505]; int v, e; i ...

  6. asp.net--mvc--异步编程

    Using Asynchronous Methods in ASP.NET MVC 4 asp.net mvc中的异步只能增加系统的性能,原来需要500个线程的,现在需要50个就够了,对一些常规的程序 ...

  7. Spring MVC REST 风格的 URL

    前言 本文主要内容为 REST 风格的 URL. REST REST(Representational State Transfer).(资源)表现层状态转化.它是一种架构风格,用 url 来访问网络 ...

  8. ZooKeeper的配置文件优化性能(转)

    一.前言 ZooKeeper的功能特性通过ZooKeeper配置文件来进行控制管理( zoo.cfg配置文件). ZooKeeper这样的设计其实是有它自身的原因的.通过前面对ZooKeeper的配置 ...

  9. Spring MVC-集成(Integration)-集成LOG4J示例(转载实践)

    以下内容翻译自:https://www.tutorialspoint.com/springmvc/springmvc_log4j.htm 说明:示例基于Spring MVC 4.1.6. 以下示例说明 ...

  10. 开源GIS软件 4

    空间数据操作框架 Apache SIS Apache SIS 是一个空间的框架,可以更好地搜索,数据聚类,归档,或任何其他相关的空间坐标表示的需要. kvwmap kvwmap是一个采用PHP开发的W ...