【环境配置】Android-Studio-OpenCV-JNI以及常见错误 ( 持续更新 )

最近一个项目要编译深度学习的库,需要用到 opencv 和 JNI,本文档用于记录环境配置中遇到的常见错误以及解决方案

Invalid Gradle JDK configuration found

failed
Invalid Gradle JDK configuration foundInvalid Gradle JDK configuration found. Open Gradle Settings 
Change JDK location

解决办法: 删除文件
.idea/gradle.xml.idea/workspace.xml, 重新编译;

解决办法:Invalid Gradle JDK configuration found

clang++: error: unknown argument: ‘-static-openmp’

原因是NDK版本过高,跟当前的AndroidStudio版本不匹配。选择升级AndroidStudio或者降低NDK版本即可。

重新下载21.3.6528147版本,配置NDK通过,rebuild项目通过,问题解决, 最新版的 Android Studio 降级到 Android Studio 4.2.1 版本,NDK 降级到 21.3.6528147;

问题:clang++.exe: error: unknown argument: ‘-static-openmp‘

NDK版本!clang++: error: unknown argument: ‘-static-openmp‘

Android res\values-v26\values-v26.xml:9:5-12:13: AAPT: error: resource android:attr/colorError not f

解决方法:
compileSdkVersion 设置为28

Android res\values-v26\values-v26.xml:9:5-12:13: AAPT: error: resource android:attr/colorError not f

2 files found with path ‘lib/arm64-v8a/xxx.so‘ 问题

最后在自己的 nativelib modulebuild.gradleandroid{} 加上

sourceSets {main {jniLibs.srcDirs = ['libs']}}

2 files found with path ‘lib/arm64-v8a/xxx.so‘ 问题

undefined reference to `cv::String::deallocate()一种可能解决方案

解决方案:替换库文件时候,同步替换头文件

undefined reference to `cv::String::deallocate()一种可能解决方案

关于解决gradle版本与gradle插件版本不一致问题的方法之一

关于解决gradle版本与gradle插件版本不一致问题的方法之一

Algorithm HmacPBESHA256 not available

D:\Android\sdk\.android 的目录下找到文件 debug.keystore, 其实不缺少签名文件,这个问题,应该是之前安装了多个版本的 Android Studio,导致签名文件被覆盖了, 删除 debug.keystore 文件,重新签名即可。

JNI GetFieldID和GetMethodID函数解释及方法签名

  1. GetFieldID 是得到 java 类中的参数 IDGetMethodID 得到 java 类中方法的 ID ,它们只能调用类中声明为 public 的参数或方法。

举例说明:

jclass c = (*env)->FindClass(env,"com/camera/webcam/Test");
jfieldID width_id = (*env)->GetFieldID(env, c, "width", "I");

第一个参数:JNI接口对象;第二个参数:Java类对象;第三个参数:参数名(或方法名);第四个参数:该参数(或方法)的签名。

  1. 方法签名

调用 JNIGetMethodID 函数获取一个 jmethodID 时,需要传入一个方法名称和方法签名,方法名称就是在 Java 中定义的方法名,方法签名的格式为:(形参参数类型列表)返回值。

JNI GetFieldID和GetMethodID函数解释及方法签名

如何从JNI返回多个数组到Java?

当您希望从一个函数返回多个“东西”时,您有两个选项(这并不是 JNI 特有的):要么创建一个包含所有结果的包装器对象(在您的例子中,是一个包含3个数组字段的 Java 类),要么使用 out 参数。也许,在您的情况下,如果您知道调用前的长度,后者可能会更容易一些。

所以,在 Java 中,您可以编写如下内容

package p;public class C {public void f() {byte[] array1 = new byte[10];int[] array2 = new int[20];String[] array3 = new String[5];fillArrays(array1, array2, array3);}native void fillArrays(byte[] byteArray, int[] intArray, String[] stringArray);
}

现在,在 C 中,这看起来是这样的:

JNIEXPORT void JNICALL 
Java_p_C_fillArrays(JNIEnv *env, jobject thisC, jbyteArray byteArray, jintArray intArray, jobjectArray stringArray)
{jboolean isCopy;jint i = 0;char* names[] = {"one", "two", "three"};jbyte *c_byteArray = (*env)->GetByteArrayElements(env, byteArray, &isCopy);for (i=0; i<(*env)->GetArrayLength(env, byteArray); i++) {c_byteArray[i] = (jbyte)i;}(*env)->ReleaseByteArrayElements(env, byteArray, c_byteArray, 0);jint *c_intArray = (*env)->GetIntArrayElements(env, intArray, &isCopy);for (i=0; i<(*env)->GetArrayLength(env, intArray); i++) {c_intArray[i] = i;}(*env)->ReleaseIntArrayElements(env, intArray, c_intArray, 0);for (i=0; i<(*env)->GetArrayLength(env, stringArray) && i<sizeof(names)/sizeof(names[0]); i++) {(*env)->SetObjectArrayElement(env, stringArray, i, (*env)->NewStringUTF(env, names[i]));}
}

如何从JNI返回多个数组到Java?

Java: JNI对数组赋值并返回给Java

JNI 中对 Java 层的数组赋值有两种方式:一是在 Java 层创建好数组,然后传递到 JNI 层,由 JNI 层进行赋值;二是直接在 JNI 层创建好数组并赋值,然后返回数组到 Java 层。下面是两种方式的对比实现:

创建两个 native 方法

    //传递数组,操作后,返回public native void passArrayMethod(int[] arr);//创建指定长度数组public native int[] createArrayMethod(int len);

生成对应的 C 函数

JNIEXPORT void JNICALL Java_com_test_git_jnidemo_JniUtil_JniDemo_passArrayMethod(JNIEnv *, jobject, jintArray);JNIEXPORT jintArray JNICALL Java_com_test_git_jnidemo_JniUtil_JniDemo_createArrayMethod(JNIEnv *, jobject, jint);

传递数组给 JNI ,修改第一个元素值,然后排序

int com(const void *a, const void *b){return *(int *)a - *(int *)b;//升序
}
JNIEXPORT void JNICALL Java_com_test_git_jnidemo_JniUtil_JniDemo_passArrayMethod(JNIEnv *env, jobject jobj, jintArray jarr){//1.获取数组指针jint *arr = env->GetIntArrayElements(jarr, NULL);*arr = 100;//2.获取数组长度int len = env->GetArrayLength(jarr);//3.排序qsort(arr, len, sizeof(jint), com);//4.释放资源env->ReleaseIntArrayElements(jarr, arr, JNI_COMMIT);
//    env->ReleaseIntArrayElements(jarr, arr, JNI_ABORT);//  对于最后一个参数(如果指针指向的数组为副本时,否则该参数不起作用)//      0       copy back the content and free the elems buffer//      JNI_COMMIT      copy back the content but do not free the elems buffer//      JNI_ABORT       free the buffer without copying back the possible changes
};

JNI 生成数组,并返回

JNIEXPORT jintArray JNICALL Java_com_test_git_jnidemo_JniUtil_JniDemo_createArrayMethod(JNIEnv *env, jobject jobj, jint len){//1.新建长度len数组jintArray jarr = env->NewIntArray(len);//2.获取数组指针jint *arr = env->GetIntArrayElements(jarr, NULL);//3.赋值int i = 0;for(; i < len; i++){arr[i] = i;}//4.释放资源env->ReleaseIntArrayElements(jarr, arr, 0);//5.返回数组return jarr;
};

MainActivity 中调用

        int[] arr = {1, 3, 2, 6, 8, 0};Log.i(TAG, "arr修改前: " + getArrayString(arr));jd.passArrayMethod(arr);Log.i(TAG, "arr修改后: " + getArrayString(arr));Log.i(TAG, "------------------------------------------");int[] arr_new = jd.createArrayMethod(10);Log.i(TAG, "arr_new: "+ getArrayString(arr_new) );

输出结果:

09-26 17:02:29.454 994-994/com.test.git.jnidemo I/MainActivity-: arr修改前: ,1,3,2,6,8,0
09-26 17:02:29.454 994-994/com.test.git.jnidemo I/MainActivity-: arr修改后: ,0,2,3,6,8,100
09-26 17:02:29.454 994-994/com.test.git.jnidemo I/MainActivity-: ------------------------------------------
09-26 17:02:29.454 994-994/com.test.git.jnidemo I/MainActivity-: arr_new: ,0,1,2,3,4,5,6,7,8,9

Java: JNI对数组赋值并返回给Java

[JNI 编程上手指南之 JNIEnv 详解]

  1. JNIEnv 是什么?

JNIEnvJava Native Interface EnvironmentJava 本地编程接口环境。JNIEnv 内部定义了很多函数用于简化我们的 JNI 编程。
JNIJava 中的所有对象或者对象数组当作一个 C 指针传递到本地方法中,这个指针指向 JVM 中的内部数据结构(对象用 jobject 来表示,而对象数组用 jobjectArray 或者具体是基本类型数组),而内部的数据结构在内存中的存储方式是不可见的。只能从 JNIEnv 指针指向的函数表中选择合适的 JNI 函数来操作 JVM 中的数据结构。

C 语言中,JNIEnv 是一个指向 JNINativeInterface_ 结构体的指针:

#ifdef __cplusplus
typedef JNIEnv_ JNIEnv;
#else
typedef const struct JNINativeInterface_ *JNIEnv; // C 语言
#endifstruct JNINativeInterface_ {void *reserved0;void *reserved1;void *reserved2;void *reserved3;jint (JNICALL *GetVersion)(JNIEnv *env);jclass (JNICALL *DefineClass)(JNIEnv *env, const char *name, jobject loader, const jbyte *buf,jsize len);jstring (JNICALL *NewStringUTF)(JNIEnv *env, const char *utf);//省略其他函数指针//......
}

JNINativeInterface_ 结构体中定义了非常多的函数指针,这些函数用于简化我们的 JNI 编程。C 语言中,JNIEnv 中函数的使用方式如下:

JNIEnv * env
// env 的实际类型是 JNINativeInterface_**
(*env)->NewStringUTF(env,"Hello from JNI !");

C++ 代码中,JNIEnv 是一个 JNIEnv_ 结构体:

#ifdef __cplusplus
typedef JNIEnv_ JNIEnv;
#else
typedef const struct JNINativeInterface_ *JNIEnv; 
#endifstruct JNIEnv_ {const struct JNINativeInterface_ *functions;
#ifdef __cplusplusjint GetVersion() {return functions->GetVersion(this);}jclass DefineClass(const char *name, jobject loader, const jbyte *buf,jsize len) {return functions->DefineClass(this, name, loader, buf, len);}jclass FindClass(const char *name) {return functions->FindClass(this, name);}jmethodID FromReflectedMethod(jobject method) {return functions->FromReflectedMethod(this,method);}jfieldID FromReflectedField(jobject field) {return functions->FromReflectedField(this,field);}jobject ToReflectedMethod(jclass cls, jmethodID methodID, jboolean isStatic) {return functions->ToReflectedMethod(this, cls, methodID, isStatic);}jclass GetSuperclass(jclass sub) {return functions->GetSuperclass(this, sub);}//省略其他函数//......
}

JNIEnv_ 结构体中同样定义了非常多的成员函数,这些函数用于简化我们的 JNI 编程。C++ 语言中,JNIEnv 中函数的使用方式如下:

//JNIEnv * env
// env 的实际类型是 JNIEnv_*
env->NewstringUTF ( "Hello from JNI ! ");

更多详情见: JNI 编程上手指南之 JNIEnv 详解

Android NDK开发:JNI实战篇

java调用本地方法–JNI访问List集合

JNI系列(四)JAVA数据类型和JNI类型对照表

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

【参考】

Android Studio配置OpenCV的JNI接口

【Android+OpenCV】Android Studio的安装全过程+在Android Studio中配置OpenCV-重点关注

NDK开发遇到的三个错误:‘javah’ 不是内部或外部命令,编码GBK的不可映射字符, 程序包XX.XX不存在

OpenCV 在 Android Studio 的使用教程

Android Studio使用OpenCV进行图像基本处理

Android学习笔记之——基于Android的opencv开发(Android studio3.6+opencv4.3.0开发环境搭建)

解决办法:Invalid Gradle JDK configuration found

NDK版本!clang++: error: unknown argument: ‘-static-openmp‘

问题:clang++.exe: error: unknown argument: ‘-static-openmp‘

Android res\values-v26\values-v26.xml:9:5-12:13: AAPT: error: resource android:attr/colorError not f

JNI GetFieldID和GetMethodID函数解释及方法签名

如何从JNI返回多个数组到Java?

Java: JNI对数组赋值并返回给Java

JNI 编程上手指南之 JNIEnv 详解

Android NDK开发:JNI实战篇

java调用本地方法–JNI访问List集合

JNI系列(四)JAVA数据类型和JNI类型对照表

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/86448.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

工业RFID在智能半导体领域的创新驱动!

在当今科技飞速发展的时代&#xff0c;半导体工业作为先锋领域&#xff0c;正不断追求更高的生产效率和产品质量。在这一挑战背后&#xff0c;RFID技术应运而生&#xff0c;为生产过程追踪和控制&#xff0c;以及在线检测和质量管理带来了前所未有的创新。通过其独特的优势&…

docker,nvidia-docker安装

卸载先前的docker Docker 的旧版本被称为 docker&#xff0c;docker.io 或 docker-engine 。如果已安装&#xff0c;请卸载它们&#xff1a; sudo apt-get remove docker docker-engine docker.io containerd runc使用 Docker 仓库进行安装 设置仓库 更新 apt 包索引 sudo…

SemrushBot蜘蛛爬虫屏蔽方式

查看访问日志时候发现有SemrushBot爬虫 屏蔽方法&#xff1a; 使用robots.txt文件是一种标准的协议,用于告诉搜索引擎哪些页面可以和不能被爬取,如想禁止Googlebot爬取整个网站的话,可以在该文件中添加以下内容: User-agent: Googlebot Disallow: / 对于遵循robots协议的蜘蛛…

linux删除文件恢复

linux文件恢复救大命 早上不小心将部署文件删除了&#xff0c;内心十分复杂&#xff0c;终于找回部分损失&#xff0c;其中一个非常重要的点是&#xff0c;文件必须得是修改过或者运行过&#xff0c;在服务器中存在进程记录 sudo su # 进入root权限 lsof | grep deploy.py在这…

助力养殖行业数字化转型,基于深度学习模型开发构建牛脸识别系统

在我们以往接触到的项目或者是业务场景中&#xff0c;大多牵涉到生物特征识别的任务基本都是人脸识别&#xff0c;这也是目前我们每天都会接触到的应用&#xff0c;比如&#xff1a;上下班的打卡、支付时的刷脸等等&#xff0c;这也是比较成熟的一项AI应用。 这里我们简单对一…

记录《现有docker中安装spark3.4.1》

基础docker环境中存储hadoop3--方便后续查看 参考&#xff1a; 实践&#xff1a; export JAVA_HOME/opt/apache/jdk1.8.0_333 export SPARK_MASTER_IP192.168.0.220 export SPARK_WORKER_MEMORY4g export SPARK_WORKER_CORES2 export SPARK_EXECUTOR_MEMORY4g export HADOOP_H…

【力扣 第 360 场周赛】题解(一题待补)

目录 2833. 距离原点最远的点2834. 找出美丽数组的最小和2835. 使子序列的和等于目标的最少操作次数TODO 2836. 在传球游戏中最大化函数值 这场比赛排名第 1 - 1000 名的参赛者 可获「NIO 蔚来」简历内推机会&#xff0c;比有的场次前十才给容易多了。 2833. 距离原点最远的点…

②matlab桌面和编辑器

目录 matlab编辑器练习 运行脚本 matlab编辑器练习 您可以通过点击灰色代码框在脚本中输入命令。 准备就绪后&#xff0c;您可以通过点击蓝色的提交按钮提交代码。 任务 在脚本中输入命令 r 3。 2.任务 在脚本中添加命令 x pi*r^2。 附加练习 当您在实时编辑器中完成…

STL-常用容器-map/ multimap容器(二叉树-红黑树)

1 map基本概念 简介&#xff1a; Map是一种关联容器&#xff0c;它通过将键和值成对存储&#xff0c;实现了快速的键值查找。在Map中&#xff0c;每个键都是唯一的&#xff0c;而值可以重复。Map容器内部使用平衡二叉树&#xff08;通常是红黑树&#xff09;的数据结构来实现高…

基于XML实现SpringIoC配置

目录 SpringIoc创建与使用的大致步骤 一.基于xml配置SpringIoc 二.基于xml配置DI 三.创建IoC容器并获取组件 SpringIoc创建与使用的大致步骤 SpringIoC的创建与使用过程分为3步 1.编写配置信息&#xff08;编写XML&#xff0c;注解、Java类&#xff09; 2.创建IoC容器&…

MySql015——使用子查询

一、创建customers表 ######################## # Create customers table ######################## use study;CREATE TABLE customers (cust_id int NOT NULL AUTO_INCREMENT,cust_name char(50) NOT NULL ,cust_address char(50) NULL ,cust_city char…

k8s 常用命令(三)

1、查看版本信息&#xff1a;kubectl version [rootmaster ~]# kubectl version [rootmaster ~]# kubectl version Client Version: version.Info{Major:"1", Minor:"21", GitVersion:"v1.21.3", GitCommit:"ca643a4d1f7bfe34773c74f7952…