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