Search code examples
javaandroidopencvjava-native-interface

Pass an array of Mats to native code


The native function I want to use requires an array of 7 Mats:

static int nativeCode(cv::Mat &inputImg, cv::Mat bufImgs[7]);

In jni_part I have:

Mat& mRgba = *(Mat*)inRgba;
Mat& bufImgs[7] = *(Mat*)inBufImgs;
nativeCode(mRgba,bufImgs);

In my Java code I'm declaring my fields:

private Mat mRgba;
private Mat[] bufImgs = new Mat[7];

I can call getNativeObjAddr on mRgba, but How do I do the equivalent for the array?

Some background:

I'm using OpenCV, doing live image processing with the camera. The function I'm calling on each frame requires some extra objects. To prevent creating and destroying these objects every frame, I'd like to create them once, and just pass references across each time.


Solution

  • You have to convert the array of Java object references into a native array of cv::Mat. Since you have a method to get the address of the native object, that's quite simple. You create a native method on the java side:

    public class MyClass {
        private Mat mRgba;
        private Mat[] bufImgs = new Mat[7];
    
        // set the fields and all...
        // ...
    
        // Call the native method
        private native int callNativeCode();
    }
    

    Then on the C/C++ side, you implement callNativeCode like this:

    JNIEXPORT jint JNICALL Java_MyClass_callNativeCode(::JNIEnv* env, jobject thisobject)
    {
        // Find the required classes
        jclass thisclass = env->GetObjectClass(thisobject);
        jclass matclass = env->FindClass("org/opencv/core/Mat");
    
        // Get methods and fields
        jmethodID getPtrMethod = env->GetMethodID(matclass, "getNativeObjAddr", "()J");
        jfieldID mrgbafieldid = env->GetFieldID(thisclass, "mRgba", "Lorg/opencv/core/Mat;");
        jfieldID bufimgsfieldid = env->GetFieldID(thisclass, "bufImgs", "[Lorg/opencv/core/Mat;");
    
        // Let's start: Get the fields
        jobject mrgba = env->GetObjectField(thisobject, mrgbafieldid);
        jobjectArray bufimgsArray = (jobjectArray)env->GetObjectField(thisobject, bufimgsfieldid);
    
        // Convert the array
        cv::Mat nativeBufImgs[7];
        for (int i = 0; i < 7; i++)
            nativeBufImgs[i] = *(cv::Mat*)env->CallLongMethod(env->GetObjectArrayElement(bufimgsArray, i), getPtrMethod);
    
        // Get the address for mRgba
        cv::Mat* mrgbaptr = (cv::Mat*)env->CallLongMethod(mrgba, getPtrMethod);
    
        // We're done! Call the method and return!
        return nativeCode(mrgbaptr, nativeBufImgs);
    }