微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何将 Array<Mat> 从 Kotlin 导入 JNI?

如何解决如何将 Array<Mat> 从 Kotlin 导入 JNI?

我是 JNI 编码新手, 所以我的问题是当我调试我的 Android Studio 时,它给了我这个“错误调用隐式删除的 'cv::Mat' 复制构造函数” 我不知道为什么。我想这是因为我如何尝试从 'jlong​​' 和 'jlong​​Array' 更改为 'Mat'。我的 native-lib.cpp 是:

JNIEXPORT jlong JNICALL
Java_com_android_example_panoramacamera_fragments_CameraFragment_imagesPass(jnienv *env,jobject thiz,jlongArray image_in_,jlong image_out_) {
    // Todo: implement imagesPass()
    Stitcher::Mode mode = Stitcher::PAnorAMA;
    Mat *image_in = (Mat*) image_in_,*image_out = (Mat*) image_out_;

    // Create a Stitcher class object with mode panoroma
    Ptr<Stitcher> stitcher = Stitcher::create(mode,false);

    // Command to stitch all the images present in the image array
    Stitcher::Status status = stitcher->stitch(*image_in,*image_out);
    if(status == Stitcher::OK){
        return (jlong) image_out;
    }
}

还有我的 kotlin-sript:

    private external fun imagesPass(imageIn: LongArray,imageOut: Long): Long

    override fun onActivityResult(requestCode: Int,resultCode: Int,data: Intent?) {
        super.onActivityResult(requestCode,resultCode,data)
        if (requestCode == pickImageCode && resultCode == RESULT_OK) {
            if (data != null) {
                if (data.clipData != null) {
                    val count = data.clipData!!.itemCount
                    for (i in 0 until count) {
                        val imageUri = data.clipData!!.getItemAt(i).uri
                        val imagestream: InputStream? = context?.contentResolver?.openInputStream(imageUri)
                        val bitmap = BitmapFactory.decodeStream(imagestream)
                        val mat = Mat()
                        Utils.bitmapToMat(bitmap,mat)
                        imagesMat[i] = mat
                    }
                }
                else {
                    val imageUri = data.data
                    val imagestream: InputStream? = imageUri?.let { context?.contentResolver?.openInputStream(it) }
                    val bitmap = BitmapFactory.decodeStream(imagestream)
                    val mat = Mat()
                    Utils.bitmapToMat(bitmap,mat)
                    imagesMat[0] = mat
                }
            }
            for(i in imagesMat.indices){
                longArray[i] = imagesMat[i].nativeObj
            }
            long = imagesPass(longArray,imageStitch.nativeObj)
            imageStitch =  Mat(long)
        }
        super.onActivityResult(requestCode,data)
    }

如您所见,我尝试导入 Mat,但由于 jni.h 的语言非常有限,我必须将 Mat 转换为 Long,以便我可以同时使用 Array 和 Mat。 但是后来我的“opencv2/core/mat.inl.hpp”开始显示错误

inline Mat _InputArray::getMat(int i) const
{
    if( kind() == MAT && i < 0 )
        return *(const Mat*)obj; //This line gets error
    return getMat_(i);
}

所以我的问题是如何从 jlong​​Array 转换为 InputArray?或者如何从 Kotlin 将数组导入 JNI? 非常感谢。

解决方法

做类似的事情

Mat *image_in = (Mat*) image_in_

是不正确的代码。出于所有实际目的,始终将所有 JNI 对象视为不透明对象,不假设它们如何存储实际底层数据,而是使用 JNI API 来操作这些对象,包括从中检索实际数据。 jlongArrayjlong array[] = {1,2,3} 之类的东西不等价

据我所知,您需要从 Java jlongArray 访问底层本机元素。有两种可能的选择:

  1. 使用 GetLongArrayElements() 获取支持的原生元素。这提供了一个原生的 jlong 数组,该数组在调用 ReleaseLongArrayElements() 之前一直有效。

  2. 使用 jlongArrayGetLongArrayRegion() 创建一系列元素的副本,该副本提供缓冲区的副本到 jlong* 缓冲区。此缓冲区的寿命与实际的 jlongArray 相关联。如果需要将此缓冲区中的元素复制回原始 jlongArray,则可以使用 SetLongArrayRegion()

一旦您可以访问本机缓冲区,就可以像往常一样在 C++ 代码中使用它们,就像 long 的数组一样。

第一种方法的解决方案示例如下所示:

Java_com_android_example_panoramacamera_fragments_CameraFragment_imagesPass
  (JNIEnv * env,jobject thiz,jlongArray imageIn,jlong ImageOut) {
      jsize len = env->GetArrayLength(imageIn);
      jlong * nativeImageList = env->GetLongArrayElements(imageIn,NULL);
      //Now one can do something like
      //Mat* image_in = reinterpret_cast<Mat*>(nativeImageList);
      //This should give the native version of images
      for(jsize idx = 0; idx < len; idx++) {
          std::printf("%zd ",nativeImageList[idx]);
      }
      std::printf("\n");
      //Once done with the array,release it back to JVM
      env->ReleaseLongArrayElements(imageIn,nativeImageList,0);
      return ImageOut;
  }

在上面这段代码中,nativeImageList 是一个 jlong 数组,它等价从 Java/Kt 层传入 {{1} }}。此 longArray 中的每个元素都将与行中存储的相同

nativeImageList

因此 longArray[i] = imagesMat[i].nativeObj 应为 nativeImageList[0] 的值,依此类推。这显然是底层图像的句柄,可以用作

imagesMat[0].nativeObj

注意区别

Mat* image_in = reinterpret_cast<Mat*>(nativeImageList);

此处,检索 native 元素,然后将其转换为 Mat* image_in = (Mat*) image_in_ ,而不是直接从 Mat* 对象中转换。

Reference

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?