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.
Related
I am going to load an image by provided file_path and then downsample it then save it. The whole thing should be done on android device.
I am in trouble to load an image on device and convert to halide::buffer.
Halide::Tools::load_image didn't work on android if I use it like
JNIEXPORT bool JNICALL Java_com_example_boxdownsample_MainActivity_downsample(
JNIEnv *env, jobject obj, jstring file_path) { ...
const char *path = env->GetStringUTFChars(file_path, NULL);
std::string work_path = path;
LOGD("the path is:%s", path);
std::string input_file = work_path + "input.png";
std::string output_file = work_path + "output.png";
Halide::Buffer<uint16_t> input = Halide::Tools::load_image(input_file);//load_image didn't work ....
int ret = box_downsample_halide(input, downsample_factor, output_u16); //box_downsample_halide is a static lib generated by halide generator
... } }
So, am I use it wrong? or
I should load it use java(that would be bitmap format) then encode it to halide::buffer, but this seems a bit hard and indirect.
Is there any easier way to do it?
Thanks!
UPDATE:
I found a way, in case who also need this, please go to my github
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 working on an example of JNI in Android Studio, the goal it to generate a Random Value and pass it to a native function which will calculate its Square and return the result in this format ( Number/Square ).
I am passing the jint number as a parameter of the function, but the result is totally wrong (the result displayed is totaly wrong).
Here is my code :
Button Generating the number and calling the native function :
Button ButtonP = (Button)findViewById(R.id.button3);
ButtonP .setOnClickListener(
new View.OnClickListener()
{
public void onClick(View view)
{
Random r = new Random();
Integer valeur = 1 + r.nextInt(10 - 1);
Log.i("Tag", "Random Value BARRAK " + valeur);
TextView tv = (TextView) findViewById(R.id.sample_text);
tv.setText(stringFromJNIStop(valeur));
}
});
The Native function:
public native String stringFromJNIStop(Integer nombre);
The implementation of the function in the cpp file:
extern "C"
JNIEXPORT jstring JNICALL
Java_fr_utbm_testjniapplication1_MainActivity_stringFromJNIStop(
JNIEnv *env,
jobject, /* this */
jint nombre) {
jint CarreNombre = nombre*nombre;
//Convertir le carré en un jstring
char bufCarreNombre[64];
sprintf(bufCarreNombre, "%d", CarreNombre); // error checking omitted
jstring jStringCarre = (*env).NewStringUTF(bufCarreNombre);
//Le convertir en un char *
const char *strCarre= (*env).GetStringUTFChars(jStringCarre,0);
//Convertir le nombre en un jstring
char bufNombre[64];
sprintf(bufNombre, "%d", nombre); // error checking omitted
jstring jStringNombre = (*env).NewStringUTF(bufNombre);
//Le convertir en char *
const char *strNombre= (*env).GetStringUTFChars(jStringNombre,0);
//Concaténer les deux
char *concatenated;
concatenated = (char *) malloc(strlen(strNombre) + strlen("/") + strlen(strCarre) + 1);
strcpy(concatenated, strNombre);
strcat(concatenated, "/");
strcat(concatenated, strCarre);
/* Create java string from our concatenated C string */
jstring retval = (*env).NewStringUTF(concatenated);
//need to release this string when done with it in order to
//avoid memory leak
(*env).ReleaseStringUTFChars(jStringNombre,strNombre);
(*env).ReleaseStringUTFChars(jStringCarre,strCarre);
/* Free the memory in concatenated */
free(concatenated);
return retval;
}
The Native function:
public native String stringFromJNIStop(Integer nombre);
The implementation of the function in the cpp file:
extern "C"
JNIEXPORT jstring JNICALL
Java_fr_utbm_testjniapplication1_MainActivity_stringFromJNIStop(
JNIEnv *env,
jobject, /* this */
jint nombre) {
This does not agree with your Java. You've changed it from int to Integer in the Java without regenerating your .h file, or you've changed or invented your .h file without reference to your .java file; or your .cpp file doesn't agree with your .h/.hpp file. Don't do this. Use javah to generate your .h/.hpp file, and redo it every time you change the native declaration(s) in your .java files, and make sure your .cpp file agrees with the .h/.hpp file. It should be:
extern "C"
JNIEXPORT jstring JNICALL
Java_fr_utbm_testjniapplication1_MainActivity_stringFromJNIStop(
JNIEnv *env,
jobject, /* this */
jobject nombre) {
where nombre refers to an Integer. However it would be better, and would always have been better, to define your Java native method as:
public native String stringFromJNIStop(int nombre);
which will now agree with your existing .cpp.
Also your .cpp should #include your .h/.hpp. Then you wouldn't have needed extern "C" or JNI_EXPORT or JNI_CALL, and the compiler may have detected the signature disagreement between .cpp and .h/.hpp.
After some reflexion, problem was resolved, in fact, in order to implement the JNI function using jint, we have to adopt the exact conversion rules in the JAVA part, so instead of declaring the random value as an integer, we must declare it as a long ! so we must work as follows :
long valeur = 1 + r.nextInt(10 - 1);
I have Android app, where I need to use C++ code. But I realised, I have problem to call C++ function. I have read something about it and tried to write something, I thought it could work. Here is my code:
private native int test(int a);
private void process() {
int ret=test(5);
Toast.makeText(this, String.valueOf(ret), Toast.LENGTH_LONG).show();
}
And my C++ code is:
#include <jni.h>
extern "C"
JNIEXPORT jint JNICALL
Java_com_example_woodem_woodem_1opencvgrains_Main_test(JNIEnv *env, jint a)
{
return a*a;
}
Of course, my real function is much more complicated and I need to pass about 6 arguments, but I hope, this can illustrate.
NOTE: Even this code doesn't work to me.
My application crash immediately after calling process(). Could you please advice me, what am I doing wrong? Compiler tells me nothing and I have no idea, where the problem is.
You are forgetting about the second argument. For example method void test() will have JNI signature JNIEXPORT void JNICALL Java..._test(JNIEnv *env, jobject thiz). In your case, edit signature to (JNIEnv *env. jobject thiz, jint a).
Edit
The previous version showed a signature for a static function. I've updated it to match instance function.
For static signature is (JNIEnv *env, jclass clazz).
You've declared your native function as private native int test(); passing an integer argument to it.
It should be private native int test(int num);
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 *