10

I have an OpenCV Android app. Most of its code is in Java but I have one function that is in C. The function gets a Mat object and returns a new one.

My question is how do I return a Mat from the native code to Java? Couldn't find any example of that.

Thanks.

2 Answers 2

27
+25

Today I had to return a Mat from native code. I started with "Tutorial 2 Advanced - 2. Mix Java+Native OpenCV" it already passes two Mat (Images captured from camera) objects to the native code. But I wanted to return extracted feature, thus I added jlong addrDescriptor to the signature:

extern "C" {
JNIEXPORT void JNICALL Java_org_opencv_samples_tutorial4_Sample4View_FindFeatures(JNIEnv* env, jobject thiz, jlong addrGray, jlong addrRgba, jlong addrDescriptor)
{
    Mat* pMatGr=(Mat*)addrGray;
    Mat* pMatRgb=(Mat*)addrRgba;
    Mat* pMatDesc=(Mat*)addrDescriptor;
    vector<KeyPoint> v;

    //OrbFeatureDetector detector(50);
    OrbFeatureDetector detector;
    OrbDescriptorExtractor  extractor;
    detector.detect(*pMatGr, v);
    extractor.compute( *pMatGr, v, *pMatDesc );
    circle(*pMatRgb, Point(100,100), 10, Scalar(5,128,255,255));
    for( size_t i = 0; i < v.size(); i++ ) {
        circle(*pMatRgb, Point(v[i].pt.x, v[i].pt.y), 10, Scalar(255,128,0,255));
    }
    }
}

In the java part I added the Mat

private Mat descriptor;
descriptor = new Mat();

The method getNativeObjAddr() does the trick. The Mat is allocated in java and its address is passed to the native code, thus there isn't any explicit returning.

FindFeatures(mGraySubmat.getNativeObjAddr(), mRgba.getNativeObjAddr(), descriptor.getNativeObjAddr());
Log.i("desc:"  , descriptor.dump());

The Mat was filled with the required data and is directly accessible in the java code after the JNI invokation returns.

Somwhere else in the code the Mat is released:

if ( descriptor != null) 
  descriptor.release();
descriptor = null;
Sign up to request clarification or add additional context in comments.

5 Comments

Hi stacker, changed my native code to this: Mat* image=(Mat*)addrDescriptor; Mat processing(image.size(), CV_8UC3); cv::medianBlur(*image, processing, 5); Now i get the following error message : jni/objDetector.cpp:23: error: request for member 'size' in 'image', which is of non-class type 'cv::Mat
@SaqibRazaq the signature is void medianBlur(const Mat& src, Mat& dst, int ksize) you need to invoke it with a reference to processing. try &processing. Or define it as Mat& processing(image.size(), CV_8UC3);
@SaqibRazaq If you want to return Mat &dst, then you should declare it in your java code and add it to the invocation of JNI method the same way you added image.
@stacker what do you mean by Somwhere else in the code the Mat is released:
@RomanticElectron that the code (last 3 lines of the post) should be invoked to release memory after the work is done.
7

in C++

jlong funC(){
Mat *mat = new Mat();
//...
return (jlong)mat;
}

in java:

long = addr;// addr is return from c method funC()
Mat mat = new Mat(addr);

Attention: You must new Mat() in C,if you code is : Mat mat();mat object memory will be collect when funC() end.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.