Jni中圖片傳遞的3種方式(轉)


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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM