Opencv machine learning model pointer convert to jlong for App activity - android

I have a Problem to convert c++ pointer to jlong. Here is my Situation: I use JNI to load pre-trained opencv machine learning model ANN_MLP(since there is no load function in opencv Android SDK) and the load function works well. But the Problem is I donn't know how to convert this c++ pointer to jlong, just as I want to return this pointer for my App. I googled but haven't fund so i just use memcpy to hold this pointer(maybe this is not the perfect method for it). One more wired Thing is, whatever I set the size of memcpy, the result buffer(here jlong resutl) has always a Offset with 8 from src buffer(here is model). Below is the code Piece what i wrote:
JNIEXPORT jlong JNICALL reader_BridgeNativeModel_nativeCreateObject
(JNIEnv *jenv, jclass, jstring jFileName){
const char* jnamestr = jenv->GetStringUTFChars(jFileName, NULL);
string stdFileName(jnamestr);
Ptr<ml::ANN_MLP> model = Algorithm::load<ml::ANN_MLP>(stdFileName)
jlong result = 0;
memcpy(&result, model, 1); // the size seems doesn't work, tried 4, 8, but got the same result as below outputs
LOGD("model address :%p\t", &model);
LOGD("result address :%p\t", &result);
....
}
// the output of log always like this
model address :0xbeed51e8
result address :0xbeed51e0
When I convert this returned jlong object as MLP pointer for prediction, I also have no idea how to convert it as model pointer:
JNIEXPORT jint JNICALL _BridgeNativeModel_nativePredict
(JNIEnv *jenv, jclass, jlong thiz, jstring jFileName,jlong src, jlong dst){
Ptr<ml::ANN_MLP> model;
printf("thiz %p\n", &thiz);
memcpy(&model, thiz, 4); // always crashed here, memcpy failed
....
}
Thanks for any suggestions in advance.
Jian

Related

Android Studio NDK return jint

I have successfully followed this tutorial https://www.youtube.com/watch?v=kFtxo7rr2HQ to learn about building NDK apps with Android Studio.
That tutorial uses a public native String HelloJNI();
That string is set in the HelloJNI.c file
#include "com_example_myapplication_MainActivity.h"
/* Header for class com_example_myapplication_MainActivity */
/*
* Class: com_example_myapplication_MainActivity
* Method: HelloJNI
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_example_myapplication_MainActivity_HelloJNI
(JNIEnv *env, jobject obj)
{
(*env)->NewStringUTF(env, "Hello from jni");
}
and loaded at runtime with
static{
System.loadLibrary("HelloJNI");
}
Now Im attempting to do the same thing but retrieve and int not a string
public native int getintONE();
I follow the same steps in the tutorial, everything works fine, now my getintONE.c reads
#include "com_example_myapplication_MainActivity.h"
/*
* Class: com_example_myapplication_MainActivity
* Method: getintONE
* Signature: ()I
*/
JNIEXPORT jint JNICALL com_example_myapplication_MainActivity_getintONE
(JNIEnv *env, jobject obj)
What is the equivelant of
JNIEXPORT jstring JNICALL Java_com_example_myapplication_MainActivity_HelloJNI
(JNIEnv *env, jobject obj)
{
(*env)->NewStringUTF(env, "Hello from jni");
}
To return an int, not a string.
I've read through many questions here, read tutorial and documentation, most of the stuff I've seen on my research and tried were samples for returning, jint arrays, converting jint to string, and what seem to me to be more involved advanced topics.
Thanks in advance
A jint is a primitive type, so if you have included jni.h you can simply return one from the function - there is no need to allocate an Object as you were doing with NewStringUTF() for a String.
JNIEXPORT jint JNICALL com_example_myapplication_MainActivity_getintONE(JNIEnv *env, jobject obj) {
return 1; //or anything that can be cast to a jint
}

Passing Json char to C using JNI to get Jansson dump of calculated values, Pointer problems

I have implemented Jansson in Android with C and made a function which calculates values from json and that works in C, I tried to use that code in NDK with JNI it builds with no errors, but as i tried to arrange the code to work with JNI it gives me pointer error warning: return from incompatible pointer type. I have read that i need to use jlong for pointers but i cant figure out how that works, it is my first time working in it.
This is my code from C (gives no errors and compiles)
char *doCalc (char *invoice_str) {
json_error_t error;
json_t *invoice = json_loads (invoice_str, JSON_DISABLE_EOF_CHECK, &error);
...
char *result = json_dumps (json_data, JSON_PRESERVE_ORDER);
return result;
}
C code Arranged to work with JNI (gives me error warning: return from incompatible pointer type, which if im correct is because of jchar)
JNIEXPORT jchar JNICALL *Java_com_example_test_doCalc (JNIEnv* env, jobject obj,char const *invoice_str) {
json_error_t error;
json_t *invoice = json_loads (invoice_str, JSON_DISABLE_EOF_CHECK, &error);
...
char *result = json_dumps (json_data, JSON_PRESERVE_ORDER);
return result;
}
Then in my Activity I like to would run doCalc(charJ);, charJ has Json in it. Which would then give me dump of calculated values.
Also I might be looking at this completely wrong, any help is appreciated.
Try to use jstring instead of char*
JNIEXPORT jchar JNICALL * Java_com_example_test_doCalc(JNIEnv * env, jobject obj, jstring invoice_jstring) {
//convert invoice_jstring to char* link bellow
json_error_t error;
json_t * invoice = json_loads(invoice_str, JSON_DISABLE_EOF_CHECK, & error);
...
char * result = json_dumps(json_data, JSON_PRESERVE_ORDER);
return result;
}
for conversion jstring to char* you can use this answer:
JNI converting jstring to char *

Android passing file path to OpenCV imread method

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.

JNI jni/cyberlevel9.c:17:31: error: request for member 'NewDirectByteBuffer' in something not a structure or union

Eclipse gives me this error when I try to build:
jni/cyberlevel9.c:17:31: error: request for member 'NewDirectByteBuffer' in something not a structure or union
jni/cyberlevel9.c:18:28: error: request for member 'NewGlobalRef' in something not a structure or union
This is the problem part of the code:
JNIEXPORT jobject JNICALL Java_com_cyberbg_natcamlevel9_NativeCameraLevel9Start_allocNativeBuffer(JNIEnv* env, jobject this, jlong size)
{
void* buffer = malloc(size);
jobject directBuffer = env->NewDirectByteBuffer(buffer, size);
jobject globalRef = env->NewGlobalRef(directBuffer);
return globalRef;
//return (NewDirectByteBuffer*)(*env)->NewDirectByteBuffer(buffer, size);
}
JNI calls from C program look like
(*env)->fun(env, p1, ...)
Your calling style is OK from C++, where a special wrapper class is defined in jni.h:
env->fun(p1, ...)
You can probably resolve your problems by simply renaming jni/cybrrlevel9.c to jni/cyberlevel9.cpp
Or,
jobject directBuffer = (*env)->NewDirectByteBuffer(env, buffer, size);
jobject globalRef = (*env)->NewGlobalRef(env, directBuffer);

JNI: How to get jbyteArray size

Background
I'm working with byte arrays in JNI. And I can't get length of jbyteArray. I'm writing code in eclipse in Windows 7.
Java code:
private native int Enroll( byte[] pSeed );
JNI code:
In JNI I have a struct that have two members unsigned long length and unsigned char data[1]
typedef struct blobData_s {
unsigned long length;
unsigned char data[1];
} blobData_t;
Now as my JNI function get as argument jbyteArray jpSeed i want to get the length of jpSeed and set it as length member of struct.
JNIEXPORT jint JNICALL Java_com_Test_Enroll( JNIEnv* env, jobject thiz, jbyteArray jpSeed ){
blobData_t* bd = malloc( sizeof(blobData_t) );
bd->length = **Question 1**
bd->data[1] = jbyteArray;
}
Question 1: How I can get the length of jpSeed in JNI ?
Question 2: Will this code works correct bd.data[1] = jbyteArray; ?
You can use GetArrayLength(JNIEnv* env, jbyteArray array) Read here.
Not sure what you want to do, I assume you want the content of jpSeed in bd.data[1].
Anyways, accessing the contents of a byte array, should be done with GetByteArrayElements(...).
Solution
Answer on Question 1. As jpSeed is jbyteArray it mean that you can get it's length by calling GetByteArrayElements( ... ) functions that declared in JNI ( you can read documentation here ) here the right code will be:
JNIEXPORT jint JNICALL Java_com_Test_Enroll( JNIEnv* env, jobject thiz, jbyteArray jpSeed ){
blobData_t* bd = malloc( sizeof(blobData_t) );
bd->length = (*env)->GetArrayLength( env, jpSeed );
.......
}
Answer on Question 2. This bd->data[1] = jbyteArray; code is not correct as it will not be compiled the right solution for this part is:
JNIEXPORT jint JNICALL Java_com_Test_Enroll( JNIEnv* env, jobject thiz, jbyteArray jpSeed ){
blobData_t* bd = malloc( sizeof(blobData_t) );
.......
jbyte* bytes = (*env)->GetByteArrayElements( env, jpSeed, 0 );
bd->data[1] = bytes[1];
}
And don't forgot to release.

Categories

Resources