java层的图片如何传递到c/c+层处理,处理完之后如何传回java层,下面总结了一下用到的三种方法。
1.将Bitmap转为int[]数组对象,将数组作为参数传递到C/C++层,处理完之后再以int[]数组返回。
1 //将bitmap转化为数组,保存到pixels中 2 Bitmap mOriginalBmp = BitmapFactory.decodeResource(getResources(), R.drawable.test); 3 int w = mOriginalBmp.getWidth(); 4 int h = mOriginalBmp.getHeight(); 5 int[] pixels = new int[w * h]; 6 mOriginalBmp.getPixels(pixels, 0, w, 0, 0, w, h); 7 8 //调用Native方法获得处理过后的数组,转化为bitmap 9 int[] resultInt = ImageProc.grayPoc(pixels, w, h); 10 Bitmap mBuildedBmp = Bitmap.createBitmap(resultInt,w, h,mOriginalBmp.getConfig()); 11 mImageView.setImageBitmap(mBuildedBmp); 12 13 //native方法定义 14 public static native int[] grayPoc(int[] pixels,int w,int h); 15 16 //native的实现,将图片转化为灰度图 17 JNIEXPORT jintArray JNICALL Java_com_dengxy_opencvtest_ImageProc_grayPoc( 18 JNIEnv * env, jclass obj, jintArray buf, int w, int h) { 19 LOGD("Java_com_dengxy_opencvtest_ImageProc_grayPoc:start"); 20 jint *cbuf; 21 cbuf = env->GetIntArrayElements(buf, JNI_FALSE); 22 23 if (cbuf == NULL) { 24 25 return 0; 26 27 } 28 Mat imgData(h, w, CV_8UC4, (unsigned char *) cbuf); 29 uchar* ptr = imgData.ptr(0); 30 31 for (int i = 0; i < w * h; i++) { 32 33 int grayScale = (int) (ptr[4 * i + 2] * 0.299 + ptr[4 * i + 1] * 0.587 + 34 35 ptr[4 * i + 0] * 0.114); 36 37 ptr[4 * i + 1] = grayScale; 38 39 ptr[4 * i + 2] = grayScale; 40 41 ptr[4 * i + 0] = grayScale; 42 43 } 44 int size = w * h; 45 jintArray result = env->NewIntArray(size); 46 env->SetIntArrayRegion(result, 0, size, cbuf); 47 env->ReleaseIntArrayElements(buf, cbuf, 0); 48 LOGD("Java_com_dengxy_opencvtest_ImageProc_grayPoc:end"); 49 return result; 50 }
这种方法需要重复的拷贝,转化图片数据,空间和时间复杂度较高,效率较低。
2.直接将Bitmap对象传递到底层,C/C++获得Bitmap数据的指针,再转化为Mat,这种方法为底层直接操作bitmap的内存空间,操作前后会锁住该地址空间,完了java层刷新界面就可以了,
这里是一个Sobel边缘检测。用的时候发现要是内存空间有拷贝,操作的不是当前图片所在的内存空间的话,图片是改变不了的。
1 Bitmap mBuildedBmp = BitmapFactory.decodeResource(getResources(), R.drawable.test); 2 ImageProc.getSobel(mBuildedBmp); 3 mImageView.setImageBitmap(mBuildedBmp); 4 5 //java接口函数 6 private static native int getSobel(Bitmap in,Bitmap out); 7 8 //对应的C++文件需要引入头文件 bitmap.h 9 #include <android/bitmap.h> 10 11 //对应C++函数 12 JNIEXPORT void JNICALL Java_com_dengxy_opencvtest_ImageProc_getSobel( 13 JNIEnv * env, jclass obj, jobject bmpIn) { 14 AndroidBitmapInfo inBmpInfo; 15 void* inPixelsAddress; 16 int ret; 17 if ((ret = AndroidBitmap_getInfo(env, bmpIn, &inBmpInfo)) < 0) { 18 LOGD("AndroidBitmap_getInfo() failed ! error=%d", ret); 19 return; 20 } 21 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); 22 if ((ret = AndroidBitmap_lockPixels(env, bmpIn, &inPixelsAddress)) < 0) { 23 LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret); 24 } 25 Mat inMat(inBmpInfo.height, inBmpInfo.width, 26 CV_8UC4, inPixelsAddress); 27 Sobel(inMat, inMat, inMat.depth(), 1, 1); 28 AndroidBitmap_unlockPixels(env, bmpIn); 29 LOGI("Return !! "); 30 return; 31 32 }
3.直接将Bitmap转化为Mat后,获取mat内存地址传到底层,处理后再返回内存地址到java层,根据地址加载Mat对象转化为bitmap。这种方法较上一种主要是内存空间有改变有可以,但是用的时候发现系统一GC回收图片,底层就出现了空指针,一看是底层MAT的析构函数没做非空判断,于是尝试着自己编译opencv4android,折腾了两天始终编译没通过,泪渀- o -
1 //Java层代码 2 Bitmap oldBmp mBuildedBmp = BitmapFactory.decodeResource(getResources(), R.drawable.test); 3 Mat bmpMat = new Mat(); 4 Utils.bitmapToMat(mBuildedBmp, bmpMat); 5 long resultAddress = -1; 6 resultAddress = ImageProc.getLaplacian(bmpMat.getNativeObjAddr()); 7 Log.d(TAG, "doLaplacian:resultAddress="+resultAddress); 8 if(resultAddress<0){ 9 return ; 10 } 11 Mat resultLaplacianMat = new Mat(resultAddress); 12 Utils.matToBitmap(resultLaplacianMat, mBuildedBmp); 13 mImageView.setImageBitmap(mBuildedBmp); 14 15 //jni接口 16 public static native long getLaplacian(long bitmap); 17 18 //c++实现 19 JNIEXPORT jlong JNICALL Java_com_dengxy_opencvtest_ImageProc_getLaplacian 20 (JNIEnv * env, jclass obj, jlong bmAddress){ 21 LOGD("Java_com_dengxy_opencvtest_ImageProc_getLaplacian:start"); 22 Mat *bitmpaMat = (Mat*) bmAddress; 23 if (NULL == bitmpaMat) { 24 LOGD("Java_com_dengxy_opencvtest_ImageProc_getLaplacian:the bitmpaMat is Null"); 25 return -1; 26 } 27 Laplacian(*bitmpaMat,*bitmpaMat,bitmpaMat->depth()); 28 jlong resultAddress = (jlong)bitmpaMat; 29 LOGD("Java_com_dengxy_opencvtest_ImageProc_getLaplacian:end"); 30 return resultAddress; 31 }
转自:http://www.apkbus.com/forum.php?mod=viewthread&tid=267283&_dsign=760031da