Search code examples
javaandroidopencvandroid-ndkjava-native-interface

How to pass a ArrayList<Mat> from Java to native side(NDK) in opencv for android


In Java side I have

List<Mat> arystrdimages = new ArrayList<Mat>();

subsequently the images read from a folder in external directory are added into the list

for(File f : strdimgs)
{       
    Mat tempimg = Highgui.imread(f.getAbsolutePath(), CvType.CV_8UC1);
    arystrdimages.add(tempimg);
}

In Native jni side I want to access arystrdimages by its reference.

For a single Mat object, we can do it by calling getNativeObjAddr method, i.e in opencv4android examples for a Mat object the accessing in native side is done as shown below

Java

private Mat mRgba;

call to native side

CallNative(mRgba.getNativeObjAddr());

In Native side

JNIEXPORT void JNICALL Java_org_opencv_samples_tutorial2_Tutorial2Activity_CallNative(JNIEnv *env, jobject thiz, jlong addrRgba1)
{
     Mat& mRgb = *(Mat*)addrRgba1;
}

How to do this for List<Mat> objects?.

EDIT: Implementation of your suggested solution

Java side

int elems = arystrdimages.size();
Log.v("Matobjdata", "number of Matobject read = " + elems);
//Log.v("Matobjdata", "from native = " + ans);
long[] tempobjadr = new long[elems]; 
for (int i=0; i<elems; i++)
{
    Mat tempaddr = arystrdimages.elementAt(i);
    tempobjadr[i] = tempaddr.getNativeObjAddr();
}

Log.v("Matobjdata", "addresselementsinlong arrray = " + tempobjadr.length);
int ans = TrainDescriptors(tempobjadr); // Call to native function
Log.v("Matobjdata", "from native = " + ans);

Native side

JNIEXPORT jint JNICALL Java_org_opencv_samples_tutorial2_Tutorial2Activity_TrainDescriptors(JNIEnv *env, jobject trainobject, jlongArray traindataaddr)
{
    vector<Mat> trainimgs;
    jsize a_len = env->GetArrayLength(traindataaddr);
    jlong *traindata = env->GetLongArrayElements(traindataaddr, 0);

    for(int k=0; k<a_len; k++)
    {
        Mat & newimage=*(Mat*)traindata[k];
        trainimgs.push_back(newimage);
    }
    // Do the required manipulation on the images; 
    env->ReleaseLongArrayElements(traindataaddr, traindata, 0);

    return a_len;
}

Solution

  • You could build, in Java, an array of long values (getNativeObjAddr() results for all the Mat) and call a native function passing the array.

    In JNI, you could access all the long values with GetArrayLength and GetLongArrayElements (which returns a jlong* to the first element).

    Use ReleaseLongArrayElements when done.