【问题标题】:OpenCV OpenCL: Convert Mat to Bitmap in JNI Layer for AndroidOpenCV OpenCL:在 Android 的 JNI 层中将 Mat 转换为位图
【发布时间】:2020-05-22 00:14:24
【问题描述】:

有几篇关于使用 Utils.matToBitmap() 函数将 Mat 转换为位图的帖子。但是我假设这个函数只能在导入 Utils 类后在 Java 层调用。

我想将数据传输到 uint32_t* bmpContent 指向的内存地址;在下面的代码中。

JNIEXPORT void JNICALL Java_com_nod_nodcv_NodCVActivity_runfilter(
    JNIEnv *env, jclass clazz, jobject outBmp, jbyteArray inData,
    jint width, jint height, jint choice, jint filter)
{
    int outsz = width*height;
    int insz = outsz + outsz/2;
    AndroidBitmapInfo bmpInfo;

    if (AndroidBitmap_getInfo(env, outBmp, &bmpInfo) < 0) {
        throwJavaException(env,"gaussianBlur","Error retrieving bitmap meta data");
        return;
    }
    if (bmpInfo.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {
        throwJavaException(env,"gaussianBlur","Expecting RGBA_8888 format");
        return;
    }
    uint32_t* bmpContent;
    if (AndroidBitmap_lockPixels(env, outBmp,(void**)&bmpContent) < 0) {
        throwJavaException(env,"gaussianBlur","Unable to lock bitmap pixels");
        return;
    }

    //This function runs the kernel on the inData and gives a matrix
    tester(env, clazz, bmpContent, outsz, inData, insz, width, height);

    AndroidBitmap_unlockPixels(env, outBmp);
}

这大致是测试器函数中发生的情况:

jbyte*  b_mat  = env->GetByteArrayElements(inData, 0);
cv::Mat mdata(h, w, CV_8UC4, (unsigned char *)b_mat); 
cv::Mat mat_src = imdecode(mdata,1); 

cv::UMat umat_src = mat_src.getUMat(cv::ACCESS_READ, cv::USAGE_ALLOCATE_DEVICE_MEMORY);
cv::UMat umat_dst (mat_src.size(), mat_src.type(), cv::ACCESS_WRITE, cv::USAGE_ALLOCATE_DEVICE_MEMORY);

kernel.args(cv::ocl::KernelArg::ReadOnlyNoSize(umat_src), cv::ocl::KernelArg::ReadWrite(umat_dst));

size_t globalThreads[3] = {static_cast<unsigned int>(mat_src.cols), static_cast<unsigned int>(mat_src.rows), 1 };

bool success = kernel.run(3, globalThreads, NULL, true);

cv::Mat mat_dst = umat_dst.getMat(cv::ACCESS_READ);

mat_dst 保存了我需要并且需要在手机上显示的结果。 我怎样才能做到这一点?

我假设我需要将数据从 mat_dst 复制到 bmpContent 位置,但我不确定。

【问题讨论】:

    标签: android opencv java-native-interface opencl


    【解决方案1】:

    使用它来将你的 Mat 转换为位图。

    jclass java_bitmap_class = (jclass)env->FindClass("android/graphics/Bitmap");
    jmethodID mid = env->GetMethodID(java_bitmap_class, "getConfig", "()Landroid/graphics/Bitmap$Config;");
    jobject bitmap_config = env->CallObjectMethod(bitmap, mid);
    jobject _bitmap = mat_to_bitmap(env,dst,false,bitmap_config);
    
    AndroidBitmap_unlockPixels(env, bitmap);
    return _bitmap;
    

    【讨论】:

      【解决方案2】:

      如果你真的需要从 JNI 层调用这个方法,你可以简单地使用 OpenCV 的原始 C++ 实现Here。 示例代码如下:

      #include <jni.h>
      #include <string>
      #include <android/bitmap.h>
      #include "opencv2/opencv.hpp"
      
      // using namespace cv;
      
      
      void MatToBitmap2 (JNIEnv * env, cv::Mat src, jobject bitmap, bool needPremultiplyAlpha)
      {
          AndroidBitmapInfo  info;
          void*              pixels = 0;
          try {
              // LOGD("nMatToBitmap");
              CV_Assert( AndroidBitmap_getInfo(env, bitmap, &info) >= 0 );
              CV_Assert( info.format == ANDROID_BITMAP_FORMAT_RGBA_8888 ||
                         info.format == ANDROID_BITMAP_FORMAT_RGB_565 );
              CV_Assert( src.dims == 2 && info.height == (uint32_t)src.rows && info.width == (uint32_t)src.cols );
              CV_Assert( src.type() == CV_8UC1 || src.type() == CV_8UC3 || src.type() == CV_8UC4 );
              CV_Assert( AndroidBitmap_lockPixels(env, bitmap, &pixels) >= 0 );
              CV_Assert( pixels );
              if( info.format == ANDROID_BITMAP_FORMAT_RGBA_8888 )
              {
                  cv::Mat tmp(info.height, info.width, CV_8UC4, pixels);
                  if(src.type() == CV_8UC1)
                  {
                      cvtColor(src, tmp, cv::COLOR_GRAY2RGBA);
                  } else if(src.type() == CV_8UC3){
                      cvtColor(src, tmp, cv::COLOR_RGB2RGBA);
                  } else if(src.type() == CV_8UC4){
                      if(needPremultiplyAlpha) cvtColor(src, tmp, cv::COLOR_RGBA2mRGBA);
                      else src.copyTo(tmp);
                  }
              } else {
                  // info.format == ANDROID_BITMAP_FORMAT_RGB_565
                  cv::Mat tmp(info.height, info.width, CV_8UC2, pixels);
                  if(src.type() == CV_8UC1)
                  {
                      cvtColor(src, tmp, cv::COLOR_GRAY2BGR565);
                  } else if(src.type() == CV_8UC3){
                      cvtColor(src, tmp, cv::COLOR_RGB2BGR565);
                  } else if(src.type() == CV_8UC4){
                      cvtColor(src, tmp, cv::COLOR_RGBA2BGR565);
                  }
              }
              AndroidBitmap_unlockPixels(env, bitmap);
              return;
          } catch(const cv::Exception& e) {
              AndroidBitmap_unlockPixels(env, bitmap);
              jclass je = env->FindClass("java/lang/Exception");
              env->ThrowNew(je, e.what());
              return;
          } catch (...) {
              AndroidBitmap_unlockPixels(env, bitmap);
              jclass je = env->FindClass("java/lang/Exception");
              env->ThrowNew(je, "Unknown exception in JNI code {nMatToBitmap}");
              return;
          }
      }
      

      该函数直接取自 OpenCV 源代码,包含针对不同格式的一些额外检查。如果您知道要使用哪种矩阵格式,则可以直接去掉检查。

      mat_dst 保存了我需要并且需要在手机上显示的结果。我该怎么做?

      你可以这样称呼:

      extern "C"
      JNIEXPORT void JNICALL
      Java_com_your_package_MainActivity_DoStuff(JNIEnv *env, jobject thiz,
                                                                     jobject bitmap) {
      // Do your stuff with mat_dst.
      
          try {
              MatToBitmap2(env, mat_dst, bitmap, false);
          }
          catch(const cv::Exception& e)
          {
              jclass je = env->FindClass("java/lang/Exception");
              env->ThrowNew(je, e.what());
          }
      }
      

      并在Java端定义它:

      public native void DoStuff(Bitmap bitmap);
      

      您不需要将任何内容返回到 java 端,因为 Bitmap 类将是引用类型,并且 MatToBitmap2 方法已经负责锁定和解锁像素缓冲区。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-10-19
        • 2018-10-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-06-22
        • 1970-01-01
        相关资源
        最近更新 更多