Ask Your Question
3

Returning a Mat from native JNI to Java

asked 2013-04-22 05:40:18 -0600

peanutman gravatar image

updated 2013-04-22 05:53:58 -0600

I have a question about mixing OpenCV's C++ and Java API. I'm using the new desktop Java API to do some processing on images, but due to Java limitations I am forced to capture the images in C++. The images are in an OS-dependant format, so I thought it would be best to convert them to the OpenCV format before handing it to the OS-independant Java code. In the android tutorials (Tutorial 2 Advanced) I saw that they instantiate a Mat on the Java side, and use getNativeObjAddr() to pass a pointer to C++, where it is used as a native C++ object. However, since I can not make any assumptions on the dimensions or channels of the images, I can not take this approach. I want Java to be able to receive the Mat object without knowing anything about it beforehand. I have nu clue how to do this correctly. I have two ideas:

1) I create a Java Mat object from the C++ side ((*env)->NewObject), use JNI to call getNativeObjAddr and work with the returned pointer. While this might work, it seems so backwards... Maybe there's a better way?

2) I create a C++ Mat, and return the pointer to Java. I'm hoping there's some kind of functionality that allows me to wrap it in a Java Mat object. The documentation mentions the Mat(long addr) constructor, but there's no further explanation, and I have no idea what it's for. Can it be used to create a Mat object from a pointer to a native Mat object?

TL;DR: How do I get a Mat created in C++ to Java ?

Thank you for reading!

edit retag flag offensive close merge delete

1 answer

Sort by ยป oldest newest most voted
5

answered 2013-04-22 06:10:48 -0600

Vladislav Vinogradov gravatar image

updated 2013-04-22 06:13:14 -0600

You can create an empty Mat in Java part and then call create method from C++:

// Java
Mat m = new Mat();
jni_func(m.getNativeObjAddr());

// C++
void jni_func(jlong matPtr)
{
    Mat* mat = (Mat*) matPtr;
    mat->create(rows, cols, type);
    memcpy(mat->data, data, mat->step * mat->rows);
}
edit flag offensive delete link more

Comments

1

Hah, I feel stupid now... I like this approach, as it doesn't require the bridge to be crossed once we're in the function. Thanks for that!

peanutman gravatar imagepeanutman ( 2013-04-23 06:43:34 -0600 )edit

Can you expand on this? I'm facing the same issue as the poster but I'm having trouble with the implementation.

I understand things on the java side. The first line in C++ makes sense. The second line corresponds to making the image (in my example case im loading it from a file with imread, long term ill get the data delivered over Ethernet, read in C++, altered by openCV in C++ then passed to java for display in a GUI).

The third line I don't understand at all. What is the second argument of memcpy?

Here is my C++ code:

void getCVMat(long matPtr) { cv::Mat * image; image = new cv::Mat(); image = (cv::Mat*) matPtr;

std::string filepath = "C:\\temp\\java.jpg";
(*image) = cv::imread(filepath);

}

This is functional, until its integrated with the main GUI where it crashed the JVM.

MattM gravatar imageMattM ( 2014-02-04 09:09:39 -0600 )edit

Question Tools

Stats

Asked: 2013-04-22 05:40:18 -0600

Seen: 11,572 times

Last updated: Apr 22 '13