• 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

  • 相关阅读:
    Linux软件管理
    Linux计划任务与进程管理
    PHP学习 Day_04
    Linux网络管理
    单播组播的实现
    Linux 下的tmpfs文件系统(/dev/shm)
    11.Linux date命令的用法
    Luogu P3783 [SDOI2017]天才黑客
    Luogu P3768 简单的数学题
    Luogu P2336 [SCOI2012]喵星球上的点名
  • 原文地址:https://www.cnblogs.com/zl1991/p/7778394.html
Copyright © 2020-2023  润新知