Jni中图片传递的3种方式(转)
java层的图片如何传递到c/c+层处理,处理完之后如何传回java层,下面总结了一下用到的三种方法。
1.将Bitmap转为int[]数组对象,将数组作为参数传递到C/C++层,处理完之后再以int[]数组返回。
//将bitmap转化为数组,保存到pixels中
Bitmap mOriginalBmp = BitmapFactory.decodeResource(getResources(), R.drawable.test);
int w = mOriginalBmp.getWidth();
int h = mOriginalBmp.getHeight();
int[] pixels = new int[w * h];
mOriginalBmp.getPixels(pixels, 0, w, 0, 0, w, h); //调用Native方法获得处理过后的数组,转化为bitmap
int[] resultInt = ImageProc.grayPoc(pixels, w, h);
Bitmap mBuildedBmp = Bitmap.createBitmap(resultInt,w, h,mOriginalBmp.getConfig());
mImageView.setImageBitmap(mBuildedBmp); //native方法定义
public static native int[] grayPoc(int[] pixels,int w,int h); //native的实现,将图片转化为灰度图
JNIEXPORT jintArray JNICALL Java_com_dengxy_opencvtest_ImageProc_grayPoc(
JNIEnv * env, jclass obj, jintArray buf, int w, int h) {
LOGD("Java_com_dengxy_opencvtest_ImageProc_grayPoc:start");
jint *cbuf;
cbuf = env->GetIntArrayElements(buf, JNI_FALSE); if (cbuf == NULL) { return 0; }
Mat imgData(h, w, CV_8UC4, (unsigned char *) cbuf);
uchar* ptr = imgData.ptr(0); for (int i = 0; i < w * h; i++) { int grayScale = (int) (ptr[4 * i + 2] * 0.299 + ptr[4 * i + 1] * 0.587 + ptr[4 * i + 0] * 0.114); ptr[4 * i + 1] = grayScale; ptr[4 * i + 2] = grayScale; ptr[4 * i + 0] = grayScale; }
int size = w * h;
jintArray result = env->NewIntArray(size);
env->SetIntArrayRegion(result, 0, size, cbuf);
env->ReleaseIntArrayElements(buf, cbuf, 0);
LOGD("Java_com_dengxy_opencvtest_ImageProc_grayPoc:end");
return result;
}
这种方法需要重复的拷贝,转化图片数据,空间和时间复杂度较高,效率较低。
2.直接将Bitmap对象传递到底层,C/C++获得Bitmap数据的指针,再转化为Mat,这种方法为底层直接操作bitmap的内存空间,操作前后会锁住该地址空间,完了java层刷新界面就可以了,
这里是一个Sobel边缘检测。用的时候发现要是内存空间有拷贝,操作的不是当前图片所在的内存空间的话,图片是改变不了的。
Bitmap mBuildedBmp = BitmapFactory.decodeResource(getResources(), R.drawable.test);
ImageProc.getSobel(mBuildedBmp);
mImageView.setImageBitmap(mBuildedBmp); //java接口函数
private static native int getSobel(Bitmap in,Bitmap out); //对应的C++文件需要引入头文件 bitmap.h
#include <android/bitmap.h> //对应C++函数
JNIEXPORT void JNICALL Java_com_dengxy_opencvtest_ImageProc_getSobel(
JNIEnv * env, jclass obj, jobject bmpIn) {
AndroidBitmapInfo inBmpInfo;
void* inPixelsAddress;
int ret;
if ((ret = AndroidBitmap_getInfo(env, bmpIn, &inBmpInfo)) < 0) {
LOGD("AndroidBitmap_getInfo() failed ! error=%d", ret);
return;
}
LOGI("original image :: width is %d; height is %d; stride is %d; format is %d;flags is %d,stride is %u", inBmpInfo.width, inBmpInfo.height, inBmpInfo.stride, inBmpInfo.format, inBmpInfo.flags, inBmpInfo.stride);
if ((ret = AndroidBitmap_lockPixels(env, bmpIn, &inPixelsAddress)) < 0) {
LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);
}
Mat inMat(inBmpInfo.height, inBmpInfo.width,
CV_8UC4, inPixelsAddress);
Sobel(inMat, inMat, inMat.depth(), 1, 1);
AndroidBitmap_unlockPixels(env, bmpIn);
LOGI("Return !! ");
return; }
3.直接将Bitmap转化为Mat后,获取mat内存地址传到底层,处理后再返回内存地址到java层,根据地址加载Mat对象转化为bitmap。这种方法较上一种主要是内存空间有改变有可以,但是用的时候发现系统一GC回收图片,底层就出现了空指针,一看是底层MAT的析构函数没做非空判断,于是尝试着自己编译opencv4android,折腾了两天始终编译没通过,泪渀- o -
//Java层代码
Bitmap oldBmp mBuildedBmp = BitmapFactory.decodeResource(getResources(), R.drawable.test);
Mat bmpMat = new Mat();
Utils.bitmapToMat(mBuildedBmp, bmpMat);
long resultAddress = -1;
resultAddress = ImageProc.getLaplacian(bmpMat.getNativeObjAddr());
Log.d(TAG, "doLaplacian:resultAddress="+resultAddress);
if(resultAddress<0){
return ;
}
Mat resultLaplacianMat = new Mat(resultAddress);
Utils.matToBitmap(resultLaplacianMat, mBuildedBmp);
mImageView.setImageBitmap(mBuildedBmp); //jni接口
public static native long getLaplacian(long bitmap); //c++实现
JNIEXPORT jlong JNICALL Java_com_dengxy_opencvtest_ImageProc_getLaplacian
(JNIEnv * env, jclass obj, jlong bmAddress){
LOGD("Java_com_dengxy_opencvtest_ImageProc_getLaplacian:start");
Mat *bitmpaMat = (Mat*) bmAddress;
if (NULL == bitmpaMat) {
LOGD("Java_com_dengxy_opencvtest_ImageProc_getLaplacian:the bitmpaMat is Null");
return -1;
}
Laplacian(*bitmpaMat,*bitmpaMat,bitmpaMat->depth());
jlong resultAddress = (jlong)bitmpaMat;
LOGD("Java_com_dengxy_opencvtest_ImageProc_getLaplacian:end");
return resultAddress;
}
转自:http://www.apkbus.com/forum.php?mod=viewthread&tid=267283&_dsign=760031da
Jni中图片传递的3种方式(转)的更多相关文章
- jQuery中开发插件的两种方式
jQuery中开发插件的两种方式(附Demo) 做web开发的基本上都会用到jQuery,jQuery插件开发两种方式:一种是类扩展的方式开发插件,jQuery添加新的全局函数(jQuery的全局函数 ...
- 城市经纬度 json 理解SignalR Main(string[] args)之args传递的几种方式 串口编程之端口 多线程详细介绍 递归一个List<T>,可自己根据需要改造为通用型。 Sql 优化解决方案
城市经纬度 json https://www.cnblogs.com/innershare/p/10723968.html 理解SignalR ASP .NET SignalR 是一个ASP .NET ...
- linux内核分析作业4:使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用
系统调用:库函数封装了系统调用,通过库函数和系统调用打交道 用户态:低级别执行状态,代码的掌控范围会受到限制. 内核态:高执行级别,代码可移植性特权指令,访问任意物理地址 为什么划分级别:如果全部特权 ...
- ios页面间传递参数四种方式
ios页面间传递参数四种方式 1.使用SharedApplication,定义一个变量来传递. 2.使用文件,或者NSUserdefault来传递 3.通过一个单例的class来传递 4.通过Dele ...
- 在Windows 10中截取截图的6种方式 简介
在Windows 10中截取截图的6种方式 简介 截图对于不同的目的很重要.它可以用于捕获笔记本电脑上的任何内容的截图.所以,如果你使用Windows 10,你可能不知道如何截图,因为它是比较新的.因 ...
- Json传递数据两种方式(json大全)
1.Json传递数据两种方式(json大全)----------------------------字符串 var list1 = ["number","name&quo ...
- LInux内核分析--使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用
实验者:江军 ID:fuchen1994 实验描述: 选择一个系统调用(13号系统调用time除外),系统调用列表参见http://codelab.shiyanlou.com/xref/linux-3 ...
- js中声明Number的五种方式
转载自:http://www.jb51.net/article/34191.htm <!DOCTYPE html> <html> <head> <meta c ...
- Python:实现图片裁剪的两种方式——Pillow和OpenCV
原文:https://blog.csdn.net/hfutdog/article/details/82351549 在这篇文章里我们聊一下Python实现图片裁剪的两种方式,一种利用了Pillow,还 ...
随机推荐
- arraylist-lambada-性能测试
package cn.com.one;import java.util.ArrayList;public class ttt { public static void main(String [] a ...
- SpringBoot 部署 docker 打包镜像
SpringBoot 部署 docker 打包镜像 环境: 1.代码编写工具:IDEA 2.打包:maven 3.docker 4.linux 7.JDK1.8 8.Xshell 9.Xftp 第一步 ...
- BFS洪水
试题描述: 已经连续下了几天雨,却还是没有停的样子.土豪CCY刚从外地赚完1e元回来,知道不久除了自己别墅,其他的地方都将会被洪水淹没. CCY所在的城市可以用一个N*M(N,M<=50)的地图 ...
- python开发_类型转换convert
在python的开发过程中,难免会遇到类型转换,这里给出常见的类型转换demo: int(x [,base ]) 将x转换为一个整数 long(x [,base ]) 将x转换为一个长整数 float ...
- SqlServer Base64解码中文
最近在做一个和拥有TurboCRM相关的项目,其中需要取出客户信息的联系人字段,经过查看,这个字段在存入时用Base64加密过了 这个功能在应用层实现是很方便的,但是由于一些特殊原因,只能放到SqlS ...
- iOS Masonry的使用需要注意的地方
自动布局最重要的是约束:UI元素间关系的数学表达式.约束包括尺寸.由优先级和阈值管理的相对位置.它们是添加剂,可能导致约束冲突 .约束不足造成布局无法确定 .这两种情况都会产生异常. 使用前:Auto ...
- javascript 手机号间隔显示 123 4567 8910
// 手机号分隔显示 let tel = this.data.tel_value // 原始手机号 let len = tel_value.length // 原始手机号的长度 let mobile ...
- EntityFramework中几种操作小结
目前项目中使用到的EntityFramework中几种操作小结,先标记下.没有详细介绍,后续有空的话再补充一些并完善一下. 列中加入RowVersion时间戳 public class Product ...
- 修改gnome-shell扩展“Applications Menu”的菜单区域宽度。
sudo打开 /usr/share/gnome-shell/extensions/apps-menu@gnome-shell-extensions.gcampax.github.com/extensi ...
- Spring ListFactoryBean实例
ListFactoryBean”类为开发者提供了一种在Spring的bean配置文件中创建一个具体的列表集合类(ArrayList和LinkedList). 这里有一个 ListFactoryBean ...