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,还 ...
随机推荐
- maven搭建企业级多模块项目
1.创建一个maven项目 选择pom 完成 2.创建模块 项目右键选择module,创建模块.创建子模块 其余的打包时都为jar 地址:https://github.com/LeviFromCN/m ...
- 【洛谷】P1156 垃圾陷阱【DP】
P1156 垃圾陷阱 题目描述 卡门――农夫约翰极其珍视的一条Holsteins奶牛――已经落了到“垃圾井”中.“垃圾井”是农夫们扔垃圾的地方,它的深度为D(2≤D≤100)英尺. 卡门想把垃圾堆起来 ...
- 同步IO与同步非阻塞IO的理解
本文图片均来自网络 一.同步IO---Blocking IO 在Blocking IO模型中,用户空间的应用程序执行一个系统调用(recvform),这会导致应用程序阻塞,直到数据准备好,并且将数据从 ...
- 读书笔记_Effective_C++_条款二十八:避免返回handlers指向对象内部成分
举个例子: class Student { private: int ID; string name; public: string& GetName() { return name; } } ...
- 快速排序及查找第K个大的数。
本文提供了一种基于分治法思想的,查找第K个大的数,可以使得时间复杂地低于nlogn. 因为快排的平均时间复杂度为nlogn,但是快排是全部序列的排序, 本文查找第k大的数,则不必对整个序列进行排序.请 ...
- 帝国cms安装在二级目录 构建中英文网站
帝国cms是很好的建站工具,一般都是安装在根目录,但是有时候租一个空间,要搭建两个网站,或者中英文双语的网站,肯定得用到二级目录 帝国cms安装二级目录步骤 1,讲安装包解压缩到要安装的二级目录下 2 ...
- 探究rh6上mysql5.6的主从、半同步、GTID多线程、SSL认证主从复制
http://407711169.blog.51cto.com/6616996/1203973/
- Andorid之Annotation框架初使用(三)
线程使用: @Background这个是使用了cached thread pool executor , 阻止开启过多的线程 可以为@Background指定一个id,用于随时终止线程的操作(Back ...
- Git使用教程(转载)
Git使用教程 一:Git是什么? Git是目前世界上最先进的分布式版本控制系统. 二:SVN与Git的最主要的区别? SVN是集中式版本控制系统,版本库是集中放在中央服务器的,而干活的时候,用的都是 ...
- poi 技术动态更新 Excel模板内容,动态更新内容
1.控制器方法 private URL base = this.getClass().getResource(""); /** * 流拍之后,可以下载询价单 * * @param ...