Error passing a cv::Mat to JNI using OpenCV on Android

5

I am developing an Android project with OpenCV and JNI.

Actually I am changing the face-detection sample.

The problem I have is that when I pass a cv::Mat reference it gives some strane output and it is not passed well.

To put you in situation, I have this in my FdActivity.java, which is the main activity of my android app:

 public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
    rgb = inputFrame.rgba();
    Mat res = mNativeDetector.process(rgb);
    return res;
}

The process function is like this:

public Mat process(Mat rgb) {
    Mat n = null;
    if(rgb.empty()) {
        System.out.println("Empty Image");
    }
    else {
        System.out.println("The image is " + rgb.rows() + "x" + rgb.cols());
        n = nativeSkinFilter(mNativeObj, rgb.getNativeObjAddr());
    }   
    return n;
}

Where nativeSkinFilter is a native function with this declaration

private static native Mat nativeSkinFilter(long thiz, long inputImage);

In the C++ side I have the function declaration (DetectionBasedTracker.h):

JNIEXPORT jlong JNICALL Java_org_opencv_samples_facedetect_DetectionBasedTracker_nativeSkinFilter (JNIEnv *, jclass, jlong);

The only thing I want to do is return the same image, just passing by the C++ function (more complex implementation will come as soon as I know I can correctly pass a matrix), so the code is just like this (DetectionBasedTracker.cpp):

JNIEXPORT jlong JNICALL Java_org_opencv_samples_facedetect_DetectionBasedTracker_nativeSkinFilter (JNIEnv * jenv,jclass,jlong rgb)
{
    Mat* rgba = (Mat*) rgb;
    if(rgb == 0) {
        LOGD("Null matrix");
    }
    else {
        LOGD("The matrix is not null. It has %i rows and %i columns", (*rgba).rows, (*rgba).cols);
    }

    return (jlong)rgb;
}

The ouptut I have is the following:

07-07 13:00:07.671: I/Choreographer(14980): Skipped 55 frames!  The application may be doing too much work on its main thread.
07-07 13:00:07.701: E/BufferQueue(14980): [unnamed-14980-0] dequeueBuffer: min undequeued buffer count (2) exceeded (dequeued=6 undequeudCount=0)
07-07 13:00:07.741: I/JavaCameraView(14980): Preview Frame received. Need to create MAT and deliver it to clients
07-07 13:00:07.741: I/JavaCameraView(14980): Frame size  is 576000
07-07 13:00:07.761: I/System.out(14980): The image is 480x800
07-07 13:00:07.761: D/FaceDetection/DetectionBasedTracker(14980): The matrix is not null. It has 1937716000 rows and 0 columns
07-07 13:00:07.761: E/cv::error()(14980): OpenCV Error: Assertion failed (src.dims == 2 && info.height == (uint32_t)src.rows && info.width == (uint32_t)src.cols) in void Java_org_opencv_android_Utils_nMatToBitmap2(JNIEnv*, jclass, jlong, jobject, jboolean), file /home/reports/ci/slave_desktop/50-SDK/opencv/modules/java/generator/src/cpp/utils.cpp, line 97
07-07 13:00:07.761: E/org.opencv.android.Utils(14980): nMatToBitmap catched cv::Exception: /home/reports/ci/slave_desktop/50-SDK/opencv/modules/java/generator/src/cpp/utils.cpp:97: error: (-215) src.dims == 2 && info.height == (uint32_t)src.rows && info.width == (uint32_t)src.cols in function void Java_org_opencv_android_Utils_nMatToBitmap2(JNIEnv*, jclass, jlong, jobject, jboolean)
07-07 13:00:07.761: A/libc(14980): Fatal signal 11 (SIGSEGV) at 0x0000000a (code=1), thread 15115 (Thread-5379)
07-07 13:00:07.791: E/BufferQueue(14980): [unnamed-14980-0] dequeueBuffer: min undequeued buffer count (2) exceeded (dequeued=5 undequeudCount=1)
07-07 13:00:07.801: I/JavaCameraView(14980): Preview Frame received. Need to create MAT and deliver it to clients
07-07 13:00:07.801: I/JavaCameraView(14980): Frame size  is 576000

I think I have tried everything, but it seems the correct way and it's still failing. Can you please please help me?

Thank you very much for your time! Help will be really appreciated.

c++
opencv
java-native-interface
parameter-passing
mat

1 Answer

2

this

JNIEXPORT jlong JNICALL Java_org_opencv_samples_facedetect_DetectionBasedTracker_nativeSkinFilter (JNIEnv *, jclass, jlong);

should be this

JNIEXPORT jlong JNICALL Java_org_opencv_samples_facedetect_DetectionBasedTracker_nativeSkinFilter (JNIEnv *, jclass, jobject, jlong);

because a call like this in java

n = nativeSkinFilter(mNativeObj, rgb.getNativeObjAddr());

expects 4 parameters:

  • JNEnv (obvious)
  • jclass is the class. Or if you are invoking the method from an instance it will be jobject
  • jobject as you are passing in some object
  • jlong now this is the actual matrix you are looking for

in the c++ side, after the second parameter, the parameters you pass in on the Java side are passed. In other words, every call via Java->C++ (whether instance or static function) on the c++ side the first 2 parameters are mandatory. Then follows your parameters between "(" and ")" in the Java code.

answered on Stack Overflow Mar 31, 2014 by over_optimistic

User contributions licensed under CC BY-SA 3.0