安卓NDK开发——常用数据std::string、jstring、cv::Mat、Bitmap互转

前言

在 Android NDK开发中,JNI可以在 Java 和本地代码(如 C、C++)之间进行通信。JNI 提供了在 Android 应用中调用本地(C/C++)代码的能力,并允许本地代码与 Java 代码相互交互。下面是在安卓上实现OCR时用到的一些常用处理函数:
在这里插入图片描述

项目中的交互与实现截图:
在这里插入图片描述
Android 应用 JNI基本步骤:

  1. C++代码: 创建 C/C++ 源代码文件,并编写所需的函数,方法或操作。使用 CMake 或 ndk-build 来构建本地代码。

  2. (JNI): 在 Java 中编写声明本地方法的接口,这些方法将调用本地代码。使用 native 关键字声明本地方法。

  3. 加载本地库: 在 Java 代码中加载已编译的本地库(.so 文件),通常使用 System.loadLibrary(“lib-name") 来加载。

  4. 使用 JNI 调用本地方法: 通过 JNI 调用在本地代码中实现的本地方法,您可以在 Java 代码中调用这些方法来执行所需的本地操作。

以下是简单的示例:

Java 代码中的 JNI 接口:

public class MyNativeClass {static {System.loadLibrary("native-lib");}public native String myNativeMethod(); // JNI 方法的声明
}

C/C++ 本地代码示例(native-lib.cpp):

#include <jni.h>extern "C" JNIEXPORT jstring JNICALL
Java_com_example_MyNativeClass_myNativeMethod(JNIEnv* env, jobject /* this */) {return env->NewStringUTF("Hello from JNI!");
}

一、 字串互转

1. jstring转std::string

std::string jstringTostring(JNIEnv *env, jstring input)
{char *str = NULL;jclass clsstring = env->FindClass("java/lang/String");jstring strencode = env->NewStringUTF("utf-8");jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");jbyteArray barr = (jbyteArray) env->CallObjectMethod(input, mid, strencode);jsize alen = env->GetArrayLength(barr);jbyte *ba = env->GetByteArrayElements(barr, JNI_FALSE);if (alen > 0) {str = (char *) malloc(alen + 1);memcpy(str, ba, alen);str[alen] = 0;}env->ReleaseByteArrayElements(barr, ba, 0);std::string ret = str;return ret;
}

2. std::string转jstring

jstring  stringToJstring(JNIEnv *env,std::string &str)
{return env->NewStringUTF(str.c_str());
}

二、图像互转

1.Bitmap转cv::Mat

将 Android 中的 Bitmap 对象转换为 OpenCV 的 cv::Mat 实现方式:

  1. 获取 Bitmap 信息: 使用 AndroidBitmap_getInfo() 函数获取 Bitmap 的信息,包括高度、宽度和像素格式。
  2. 锁定 Bitmap 像素: 使用 AndroidBitmap_lockPixels() 锁定 Bitmap 像素以访问像素数据。
  3. 创建 cv::Mat 对象: 使用 cv::Mat 构造函数创建一个与 Bitmap 数据对应的 cv::Mat 对象,确保使用与 Bitmap 相同的宽度、高度和像素格式。在构造函数中,传递 Bitmap 的高度、宽度、图像类型以及像素数据的指针。
  4. 解锁 Bitmap: 使用 AndroidBitmap_unlockPixels() 解锁 Bitmap 像素。

确保在 JNI 中正确地调用此函数,并在使用完毕后释放返回的 cv::Mat 对象以避免内存泄漏。

void bitmapToMat(JNIEnv *env, jobject bitmap, Mat &dst) {AndroidBitmapInfo info;void *pixels = 0;try {LOGI("nBitmapToMat");CV_Assert(AndroidBitmap_getInfo(env, bitmap, &info) >= 0);CV_Assert(info.format == ANDROID_BITMAP_FORMAT_RGBA_8888 ||info.format == ANDROID_BITMAP_FORMAT_RGB_565);CV_Assert(AndroidBitmap_lockPixels(env, bitmap, &pixels) >= 0);CV_Assert(pixels);dst.create(info.height, info.width, CV_8UC4);if (info.format == ANDROID_BITMAP_FORMAT_RGBA_8888) {LOGI("nBitmapToMat: RGBA_8888 -> CV_8UC4");Mat tmp(info.height, info.width, CV_8UC4, pixels);//if (needUnPremultiplyAlpha) cvtColor(tmp, dst, COLOR_mRGBA2RGBA);//elsetmp.copyTo(dst);} else {// info.format == ANDROID_BITMAP_FORMAT_RGB_565LOGI("nBitmapToMat: RGB_565 -> CV_8UC4");Mat tmp(info.height, info.width, CV_8UC2, pixels);cvtColor(tmp, dst, COLOR_BGR5652RGBA);}AndroidBitmap_unlockPixels(env, bitmap);return;} /*catch (const cv::Exception &e) {AndroidBitmap_unlockPixels(env, bitmap);LOGE("nBitmapToMat caught cv::Exception: %s", e.what());jclass je = env->FindClass("java/lang/Exception");if (!je) je = env->FindClass("java/lang/Exception");env->ThrowNew(je, e.what());return;}*/ catch (...) {AndroidBitmap_unlockPixels(env, bitmap);LOGE("nBitmapToMat caught unknown exception (...)");jclass je = env->FindClass("java/lang/Exception");env->ThrowNew(je, "Unknown exception in JNI code {nBitmapToMat}");return;}
}

2.cv::Mat转Bitmap

  1. 创建 Bitmap 对象: 使用 Android 的 Bitmap 创建方法,根据 cv::Mat 的像素格式和尺寸创建一个对应的 Bitmap 对象。
  2. 锁定 Bitmap 像素: 使用 AndroidBitmap_lockPixels() 锁定 Bitmap 像素以访问像素数据。
  3. 将 cv::Mat 数据复制到 Bitmap:cv::Mat 数据复制到 Bitmap 对象中。
  4. 解锁 Bitmap: 使用 AndroidBitmap_unlockPixels() 解锁 Bitmap 像素。
void matToBitmap(JNIEnv *env, cv::Mat &src, jobject bitmap) {AndroidBitmapInfo info;void *pixels = 0;try {LOGI("nMatToBitmap");CV_Assert(AndroidBitmap_getInfo(env, bitmap, &info) >= 0);CV_Assert(info.format == ANDROID_BITMAP_FORMAT_RGBA_8888 ||info.format == ANDROID_BITMAP_FORMAT_RGB_565);CV_Assert(src.dims == 2 && info.height == (uint32_t) src.rows &&info.width == (uint32_t) src.cols);CV_Assert(src.type() == CV_8UC1 || src.type() == CV_8UC3 || src.type() == CV_8UC4);CV_Assert(AndroidBitmap_lockPixels(env, bitmap, &pixels) >= 0);CV_Assert(pixels);if (info.format == ANDROID_BITMAP_FORMAT_RGBA_8888) {Mat tmp(info.height, info.width, CV_8UC4, pixels);if (src.type() == CV_8UC1) {LOGI("nMatToBitmap: CV_8UC1 -> RGBA_8888");cvtColor(src, tmp, COLOR_GRAY2RGBA);} else if (src.type() == CV_8UC3) {LOGI("nMatToBitmap: CV_8UC3 -> RGBA_8888");cvtColor(src, tmp, COLOR_RGB2RGBA);} else if (src.type() == CV_8UC4) {LOGI("nMatToBitmap: CV_8UC4 -> RGBA_8888");//if (needPremultiplyAlpha) cvtColor(src, tmp, COLOR_RGBA2mRGBA);//elsesrc.copyTo(tmp);}} else {// info.format == ANDROID_BITMAP_FORMAT_RGB_565Mat tmp(info.height, info.width, CV_8UC2, pixels);if (src.type() == CV_8UC1) {LOGI("nMatToBitmap: CV_8UC1 -> RGB_565");cvtColor(src, tmp, COLOR_GRAY2BGR565);} else if (src.type() == CV_8UC3) {LOGI("nMatToBitmap: CV_8UC3 -> RGB_565");cvtColor(src, tmp, COLOR_RGB2BGR565);} else if (src.type() == CV_8UC4) {LOGI("nMatToBitmap: CV_8UC4 -> RGB_565");cvtColor(src, tmp, COLOR_RGBA2BGR565);}}AndroidBitmap_unlockPixels(env, bitmap);return;} /*catch (const cv::Exception &e) {AndroidBitmap_unlockPixels(env, bitmap);LOGE("nMatToBitmap caught cv::Exception: %s", e.what());jclass je = env->FindClass("java/lang/Exception");if (!je) je = env->FindClass("java/lang/Exception");env->ThrowNew(je, e.what());return;}*/ catch (...) {AndroidBitmap_unlockPixels(env, bitmap);LOGE("nMatToBitmap caught unknown exception (...)");jclass je = env->FindClass("java/lang/Exception");env->ThrowNew(je, "Unknown exception in JNI code {nMatToBitmap}");return;}
}

3.C++中创建Bitmap

jobject generateBitmap(JNIEnv *env, uint32_t width, uint32_t height)
{jclass bitmapCls = env->FindClass("android/graphics/Bitmap");jmethodID createBitmapFunction = env->GetStaticMethodID(bitmapCls,"createBitmap","(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;");jstring configName = env->NewStringUTF("ARGB_8888");jclass bitmapConfigClass = env->FindClass("android/graphics/Bitmap$Config");jmethodID valueOfBitmapConfigFunction = env->GetStaticMethodID(bitmapConfigClass, "valueOf","(Ljava/lang/String;)Landroid/graphics/Bitmap$Config;");jobject bitmapConfig = env->CallStaticObjectMethod(bitmapConfigClass,valueOfBitmapConfigFunction, configName);jobject newBitmap = env->CallStaticObjectMethod(bitmapCls,createBitmapFunction,width,height, bitmapConfig);return newBitmap;
}

4.Java传送图像到JNI层

java层实现图像读取与发送:

 private void initTemplate() throws IOException{//用io流读取二进制文件,最后存入到byte[]数组中InputStream in = getAssets().open("template.jpg");//证件模型文件int length = in.available();byte[] buffer = new byte[length];in.read(buffer);//转换为BitmapBitmapFactory.Options opts = new BitmapFactory.Options();Bitmap template = BitmapFactory.decodeByteArray(buffer, 0, buffer.length, opts);int width = template.getWidth();int height = template.getHeight();int[] pixArr = new int[width*height];template.getPixels(pixArr,0,width,0,0,width,height);int rt = scan_jia_sim.sendTemplate(pixArr,width,height);}

JNI层实现接=收:

extern "C"
JNIEXPORT int JNICALL
Java_com_dashu_scanjia_ScanJiaSim_sendTemplate(JNIEnv *env, jobject instance, jintArray pix_, jint w, jint h)
{jint *pix = env->GetIntArrayElements(pix_, NULL);if (pix == NULL){return -1;}//将c++图片转成Opencv图片cv::Mat cv_temp(h, w, CV_8UC4, (unsigned char *) pix);if(cv_temp.empty()){return -2;}cv_template = cv_temp.clone();return 0;
}

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

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

相关文章

Linux指令学习

目录 1.ls指令 2.pwd命令 3.cd 指令 4. touch指令 5.mkdir指令 6.rmdir指令 && rm 指令 7.man指令 8.cp指令 9.mv指令 10.cat指令 11.more指令 12.less指令 13.head指令 14.find指令&#xff1a; -name 15.grep指令 16.zip/unzip指令&#xff1a; 17.tar…

基于SpringBoot+Thymeleaf+Mybatis学生信息管理系统(源码+数据库)

一、项目简介 本项目是一套基于SpringBootThymeleafMybatis学生信息管理系统&#xff0c;主要针对计算机相关专业的正在做bishe的学生和需要项目实战练习的Java学习者。 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目可以直接作为bishe使用。 项目都经过严格调试…

Densely Connected Convolutional Networks(2018.1)

文章目录 Abstract1. Introduction提出问题以前的解决方法我们的方法效果 2. Related Work3. DenseNetsResNets.Dense connectivity.Composite function.Pooling layers.Growth rate.Bottleneck layers.Compression.Implementation Details. 4. Experiments5. DiscussionModel …

AI并行计算:CUDA和ROCm

1 介绍 1.1 CUDA CUDA&#xff08;Compute Unified Device Architecture&#xff09;是Nvidia于2006年推出的一套通用并行计算架构&#xff0c;旨在解决在GPU上的并行计算问题。其易用性和便捷性能够方便开发者方便的进行GPU编程&#xff0c;充分利用GPU的并行能力&#xff0…

(使用vite搭建vue3项目(vite + vue3 + vue router + pinia + element plus))

使用vite搭建vue3项目&#xff08;vite vue3 vue router pinia element plus&#xff09; 初始化项目安装依赖&#xff0c;运行项目初始配置 初始化项目 1.需要在创建项目的位置cmd目录下执行 2. npm init vitelatest 回车 npm init vitelatest3.填上自己的项目名称 回车…

ELK(三)—安装可视化工具

目录复制 目录 一、ElasticSearch-Head可视化工具介绍1.1特性&#xff1a;1.2用法&#xff1a; 二、安装2.1docker安装2.2Chrome插件安装 一、ElasticSearch-Head可视化工具介绍 ElasticSearch-Head 是一个基于浏览器的 Elasticsearch 可视化工具&#xff0c;它提供了一个直观…

JSON字符串转泛型对象

JSON字符串转泛型对象 以下问题只仅限于博主自身遇到&#xff0c;不代表绝对出现问题 相关类展示&#xff1a; 参数基类 public class BaseParams { }基类 public abstract class AbstractPush<Params extends BaseParams> {protected abstract void execute(Params…

mysql数据库中int字段长度,即int(1)和int(10)的区别

1.起因 为什么想起来看这个问题&#xff0c;是最近有同事问mysql的init类型的字段长度的问题&#xff0c;他问int(1)和int(10)是什么意思&#xff0c;是字段长度越大&#xff0c;能存储的数字越大么&#xff1f;咋一问&#xff0c;还有点懵&#xff0c;从惯性思维来看&#xf…

论文分享 | 基于机载单目视觉的四旋翼无人机群内相对定位

阿木实验室推出的开源项目校园赞助活动&#xff0c;再次迎来开发者参与&#xff01; 国防科技大学电子对抗学院司晓坤同学&#xff0c;在Prometheus开源仿真架构的基础上进行了二次开发&#xff0c;且使用Prometheus 450&#xff08;P450&#xff09;进行了真机实验并发表了相…

12月8日星期五今日早报简报微语报早读

12月8日星期五&#xff0c;农历十月廿六&#xff0c;早报微语早读。 1、广东男篮官宣&#xff1a;易建联9号球衣退役12月29日 正好首秀21周年&#xff1b; 2、2024届全国普通高校毕业生规模预计达1179万人&#xff1b; 3、国务院&#xff1a;严禁新增钢铁产能 严格合理控制煤…

leetcode面试经典150题——35 螺旋矩阵

题目&#xff1a; 螺旋矩阵 描述&#xff1a; 给你一个 m 行 n 列的矩阵 matrix &#xff0c;请按照 顺时针螺旋顺序 &#xff0c;返回矩阵中的所有元素。 示例&#xff1a; 输入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,9]] 输出&#xff1a;[1,2,3,6,9,8,7,4,5] 提示&…

Linux centos8安装JDK1.8、tomcat

一、安装jdk 1.如果之前安装过jdk&#xff0c;先卸载掉旧的 rpm -qa | grep -i jdk 2.检查yum中有没有java1.8的包 yum list java-1.8* 3.yum安装jdk yum install java-1.8.0-openjdk* -y 4.验证 二、安装tomcat Index of /tomcat 可以在这里选择你想要安装的tomcat版本…