I want to know how to get a custom object from Java to c++?
I need to implement a method in c++ for get performance. I already have the method working in java but I want to port to c++.
On Java a I call the method like this:
private native boolean P(Mat Previous, String Name);
On CPP file I need to get the mat object. Getting string is easy! But how can I get the custom mat object similar to c++(cv::Mat)? I need to get java Mat into a cv::Mat.
Here the cpp file:
JNIEXPORT bool JNICALL Java_br_raphael_detector_SimpsonDetector_P
(JNIEnv* env,jobject thiz, jobject Previous, jstring Name){
jboolean sim = false;
const char* N = env->GetStringUTFChars(Name,0);
std::string Nome = N;
//Release
env->ReleaseStringUTFChars(Name,N);
//Then Return
return sim;
}
A java Mat object is a totally different thing from a native cv::Mat, you can't get one directly from the other.
That said, if you know what fields are inside Mat, and you know the corresponding fields in cv::Mat, you can write a conversion function that copies the contents of the fields one-by-one.
// First get the Mat class
jclass Mat = (*env)->GetObjectClass(env, Previous);
// To get a field
jfieldId field = (*env)->GetFieldID(env, Mat, "fieldName", field type);
// To get a method
jmethodId method = (*env)->GetMethodID(env, Mat, "methodName", method signature);
from there you can read the values of fields, or call methods
// getting a field
(*env)->GetObjectField(env, Previous, field);
// calling a method
(*env)->CallObjectMethod(env, Previous, method, parameters);
refer to http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/functions.html for details
I'm one year late to the party, but the way you pass a Mat to C is with a jlong with the address of the Java's Mat. You can do something like this:
private static native boolean P(long matAddress, String name);
In C:
JNIEXPORT jboolean JNICALL Java_br_raphael_detector_SimpsonDetector_P
(JNIEnv* env,jobject thiz, jlong matAddress, jstring Name)
{
cv::Mat* image = (cv::Mat*)matAddress;
// Do stuff with image.
}
Then you would call the method in Java like this:
P(myMat.getNativeObjAddr(), name);
OpenCV exposes this method just for cases like this. (I would link to the documentation's page but the website is not loading here, sorry.)
Related
I call a function in C++ from java. In java I have an array of Strings that I want to use in my C++-function.
I have in C++:
std::string names[6]; // Global variable
extern "C"
JNIEXPORT void JNICALL
Java_com_erikbylow_mycamera3_JNIUtils_updateStandingBoard(JNIEnv *env, jobject type, std::string *names, jint nbrElements){
memcpy(standingText, names, 6* sizeof(std::string));
nbrStandText = nbrElements;
}
In `Java`:
public static void updateStanding( String resultArray[]){
updateStandingBoard(resultArray, resultArray.length);
}
What is the simplest way of achieving what I want? When I try this and different variants it either crashes or yields nonsense data.
JNI is a primarily a C API, it doesn't know anything about std::string as you can validate by calling javah on the Java source file contained the native methods declaration.
Also Java isn't C, there is no need to pass the array size as additional parameter.
So your native void updateStandingBoard(String[] result, int size) should actually be native void updateStandingBoard(String[] result)
With this in mind, the JNI code should be
std::vector<std::string> names; // much safer or use std::array as alternative
extern "C"
JNIEXPORT void JNICALL
Java_com_erikbylow_mycamera3_JNIUtils_updateStandingBoard(JNIEnv *env, jobject type, jobjectArray names) {
jint nbrElements = env->GetArrayLength(names);
// now copy the strings into C++ world
for (int i = 0; i < nbrElements ; i++) {
// access the current string element
jobject elem = env->GetObjectArrayElement(names, i);
jsize length = env->GetStringLength(elem);
// pin it to avoid GC moving it around during the copy
const jchar *str = env->GetStringChars(elem, nullptr);
names.push_back(std::string(str, length));
// make it available again to the VM
env->ReleaseStringChars(elem, str);
}
}
This was just for the basic strings, if you are interested in UTF strings, then you should make use of std::wstring and the UTF variants of the above JNI functions.
I am trying to use openCV in my android project and trying to run this native code but I don't know how to use this parameter
JNIEXPORT jint JNICALL Java_com_example_helloopencvactivity_nativecalls_filepath
(JNIEnv * env, jobject jo, jstring str1, jstring str2) {
cv::Mat img1 = cv::imread("");
}
I tried using this
const char *nativeString = (*env)->GetStringUTFChars(env, str1, 0);
cv::Mat img1 = cv::imread(nativeString);
but i am getting this error error: no matching function for call to '_JNIEnv::GetStringUTFChars
I need to pass the file path from android file system to openCV's native code for processing, the passing element is string and should be read by imread
first in the java side, my codes looks likeļ¼
private String path="/mnt/sdcard/";
InitFeature(width,height,path);
public native void InitFeature(int width, int height,String path);
then in the jni side, it's:
//passed from the java part and release after InitFreature
const char* nPath;
//to save the globle path
char* g_path;
JNIEXPORT void JNICALL Java_org_opencv_samples_tutorial6_Tutorial2Activity_InitFeature(JNIEnv* env, jobject,jint width,jint height,jstring path);
JNIEXPORT void JNICALL Java_org_opencv_samples_tutorial6_Tutorial2Activity_InitFeature(JNIEnv* env, jobject,jint width,jint height,jstring path)
{
//jsize path_size;
nPath=env->GetStringUTFChars(path,NULL);
//path_size=env->GetArrayLength(path);
LOGD("path: %s \n",nPath);
int length=strlen(nPath);
LOGD("length: %d \n",length);
g_path=new char[length+1];
memcpy(g_path,nPath,length+1);
LOGD("path_2: %s \n",g_path);
LOGD("length: %d \n",strlen(g_path));
char l_path[128];
strcpy(l_path,g_path);
strcat(l_path,"color.jpg");
LOGD("path_3: %s \n",l_path);
LOGD("length: %d \n",sizeof(l_path));
m_width=width;
m_height=height;
center.x=float (m_width/2.0+0.5);//float (Img_tmp->width/2.0+0.5);
center.y=float (m_width/2.0+0.5);//float (Img_tmp->height/2.0+0.5);
env->ReleaseStringUTFChars(path,nPath);
}
since I have different native calls, one to initiate features(shown here) and others to process every frame, and after you env->ReleaseStringUTFChars(path,nPath); the string would be invisible to jni part. I have the copy the string to a global char* g_path;
and a little sample is here as well, the file path is "/mnt/sdcard/color.jpg" and check those logs.
then you can use imread() to get this jpg.
I use other libs like libjpg, so I am not showing the codes here.
I am having a hard time finding an answer to this. But, what is "jboject thiz" used for in JNI function calls? For example:
jobjectArray Java_com_gnychis_awmon_Test( JNIEnv* env, jobject thiz ) {
I use env to allocate objects often, but I've never used thiz and I'm not sure what it is for. Just for knowledge purposes.
The following is a JNI wrapper function which has two parameters, and returns a primitive array of objects:
jobjectArray Java_com_gnychis_awmon_Test( JNIEnv* env, jobject thiz );
From the function name you have given I don't think it is complete, that is, you haven't respected the obligatory function name convention which is:
Start the function with Java_
Append the package name separated by _ (undescores) i.e. com_company_awesomeapp. So far the function name is composed of: Java_com_company_awesomeapp
Append the Java class name where the native method has been defined,
followed by the actual function name. So at this point we should have the following function name: Java_com_company_awesomeapp_MainActivity_Test
The first parameter is a pointer to a structure storing all JNI function pointers, i.e. all the predefined functions you have available after you #include <jni.h>.
The second parameter is a reference to the Java object inside which this native method has been declared in. You can use it to call the other methods of the Java object from the current JNI function, i.e. Call Java instance methods from JNI code written in C or C++.
If for example you have the following Java class inside the MainActivity.java file:
public class MainActivity extends Activity
{
static
{
try
{
System.loadLibrary("mynativelib");
}
catch (UnsatisfiedLinkError ule)
{
Log.e(TAG, "WARNING: Could not load native library: " + ule.getMessage());
}
}
public static native Object[] Test();
}
Then, the jobject thiz parameter of the JNI function would be a reference to an object of type MainActivity.
I found this link that should help clarify the question.
https://library.vuforia.com/articles/Solution/How-To-Communicate-Between-Java-and-C-using-the-JNI
Here is an example in it that uses the "jobject".
JNIEXPORT void JNICALL
Java_com_qualcomm_QCARSamples_ImageTargets_ImageTargets_initApplicationNative(
JNIEnv* env, jobject obj, jint width, jint height)
{
...
jclass activityClass = env->GetObjectClass(obj);
jmethodID getTextureCountMethodID = env->GetMethodID(activityClass,
"getTextureCount", "()I");
if (getTextureCountMethodID == 0)
{
LOG("Function getTextureCount() not found.");
return;
}
textureCount = env->CallIntMethod(obj, getTextureCountMethodID);
...
}
jobject thiz means the this in java class.
Sometimes if you create a static native method like this.
void Java_MyClass_method1 (JNIEnv *, jclass);
jclass means the class itself.
I want to call the Java method from Jni code with the int and int[] arguments. for that i have Go-ogled and found the following sample .
Calling a java method from c++ in Android
And it worked fine with String parameter . But While trying with int i got issues .
Please help me .
JNI CODE:
jstring Java_com_calljavafromjni_MainActivity_getJniString( JNIEnv* env, jobject obj){
jstring jstr = (*env)->NewStringUTF(env, "RAJESH TEST from JNI ");
jint sss=1111;
jclass clazz = (*env)->FindClass(env, "com/calljavafromjni/MainActivity");
jmethodID messageMe = (*env)->GetMethodID(env, clazz, "messageMe", "(Ljava/lang/String;)Ljava/lang/Integer;");
jobject result = (*env)->CallObjectMethod(env, obj, messageMe, sss);
const char* str = (*env)->GetStringUTFChars(env,(jstring) result, NULL); // should be released but what a heck, it's a tutorial :)
printf("%s\n", str);
return (*env)->NewStringUTF(env, str);
}
Java code
public String messageMe(Integer text) {
System.out.println( "aaaaaaaaaaaaaaaa "+text);
return "test";
}
I don't see where int[] come into your problem, but with int it should be easy to solve.
You need to look at your GetMethodId() call, specifically the method signature argument (the last one). The JNI Specification provides a list of all its Type Signatures here. That should also help you when you eventually come to pass your int arrays too.
So we can see at the moment your signature is:
String messageMe(Integer text)
but you told JNI it was (Ljava/lang/String;)Ljava/lang/Integer; which translates to something like:
java.lang.Integer messageMe(String text)
The Type Signatures show us that the signature for an int is simply I so your argument for GetMethodId() should be something like this:
jmethodID messageMe = (*env)->GetMethodID(env, clazz, "messageMe", "(I)Ljava/lang/String;");
I hope that helps. As I said before, JNI isn't the easiest thing to get into but the answers really are all in the Specification, you just have to look quite hard.
EDIT: I corrected my signature.
Basically, you were almost there - you just got the arguments and return value the wrong way around in the signature. It should be (<arguments>)<return type>. You also made the easy mistake of specifying the class for Integer, instead of the primitive type.
I need to get name of my android application from the native side somethin like that:
android.content.context context=(android.content.context) this;//current activiy
Resources appR =context.getResources();
String packageName=context.getPackageName();
int id=appR.getIdentifier("app_name","string",packageName );
CharSequence txt = appR.getText(id);
my native code like that:
jstring Java_com_AnalyticToolC_AnalyticToolActivity_JNISendData(JNIEnv* env,jobject entryObject,jobject contxt)
{
char *realAppName;
realAppName=(char *)malloc(16 * 1024);
jclass android_content_Context =(*env)->GetObjectClass(env, contxt);
jmethodID midGetPackageName = (*env)->GetMethodID(env, android_content_Context, "getPackageName", "()Ljava/lang/String");
jstring packageName=(*env)->CallObjectMethod(env, contxt, midGetPackageName);
jmethodID midGetResources = (*env)->GetMethodID(env, android_content_Context, "getResources", "()L");
jobject jResource=(*env)->CallObjectMethod(env, context, midGetResources);
jclass resource_Class=(*env)->GetObjectClass(env, jResource);
jmethodID midGetIdentifier = (*env)->GetMethodID(env, resource_Class, "getIdentifier", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String)I");
jstring app_name=(*env)->NewStringUTF(env,"app_name");
jstring TypeName=(*env)->NewStringUTF(env,"string");
int id=(*env)->CallObjectMethod(env, jResource, midGetIdentifier,app_name,TypeName,packageName);
jmethodID midGetAppName = (*env)->GetMethodID(env, resource_Class,"getText","(I)Ljava/lang/String");
jstring appName=(*env)->CallObjectMethod(env, jResource, midGetAppName,id);
realAppName=(*env)->GetStringUTFChars(env, appName, NULL);
}
and i just pass the activity to my native methon from java code.
and i don't have a chance to write this code in java class then call it form my NDK application
I'm trying a lot to pass a context object as jobject to my native code but it always crash.
dose any one have any idea?
Reflected Java access in C is ugly, ugly, ugly, just like you've demonstrated. Pass the app name as an extra string parameter.
EDIT: OK, you want reflection, reflection you'll get.
Your native method belongs to class AnalyticToolActivity. As a nonstatic class method, it has a this pointer on every call. Unlike C++ and Java methods, this pointer is passed explicitly as the second parameter. The method has two mandatory parameters - a JNIEnv * and a jobject. The second one corresponds to the this pointer of the Java object.
So if your AnalyticToolActivity is a subclass of Activity - quite likely - the entryObject parameter is an instance of Activity, meaning it's an instance of Context. So get rid of the third parameter (contxt), and your JNI code can go like this:
jclass android_content_Context =(*env)->GetObjectClass(env, entryObject);
//or use FindClass
jmethodID midGetPackageName = (*env)->GetMethodID(env,
android_content_Context,
"getPackageName",
"()Ljava/lang/String;");
jstring packageName=(*env)->CallObjectMethod(env, entryObject, midGetPackageName);
and so forth.
Why do you need to do so from the NDK? Perhaps it would be more useful for us to help you debug the problem passing a context object, and then you could just pass the app name as a string.