I am developing an android app using C++ code. Trying to use JNI but failed.
The code in myFirstApp.cpp
JNIEXPORT jint JNICALL Java_com_example_myfirstapp_CreateApp_findMarkersNative(
JNIEnv* env, jobject, jlong addrRgba) {
//clock_t begin = clock();
Mat& mRgb = *(Mat*) addrRgba;
Mat mgray(mRgb.rows, mRgb.cols, CV_8UC1);
cvtColor(mRgb, mgray, CV_RGBA2GRAY, 1); // the working one
clearVectors();
findSquares(mgray);
mergeRectangles();
processFilteredSquares(mgray);
drawFilteredSquaresWithoutMarker(mRgb);
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "Candidates %i",candidates.size());
return clusterBoundaries.size();
// clock_t end = clock();
// mgray.release();
}
In the android activity(CreateApp), I've declared the method
public native int findMarkersNative(long imgAdd);
The package name in the activity is
package com.example.myfirstapp;
The error appearing the logcat
Caused by: java.lang.UnsatisfiedLinkError: Native method not found com.example.myfirstapp.CreateApp.findMarkersNative
Your definitions seem correct. According to several similar posts, it may be because of C / C++ name mangling.
Try surrounding your methods, around where this API is defined with
extern "C" { }
for example:
extern "C" {
JNIEXPORT jint JNICALL Java_com_example_myfirstapp_CreateApp_findMarkersNative(JNIEnv* env, jobject, jlong addrRgba)
{
... function code ...
}
}
Source: Unsatisfied link error
Related
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
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
}
I am trying to compile my jnicode it showing error
_JNIEnv::GetShortArrayElements(JNIEnv*&, _jshortArray*&, int)'
my code is:
extern "C" JNIEXPORT jint Java_com_techgentsia_sound_Opusmain_nativeDecodeBytes (JNIEnv *env, jobject thiz,jbyteArray decoder_insrc,jshortArray decoder_out)
{
int frame_size=320;
jshort* pcm_data_decoder=env->GetShortArrayElements(env, decoder_out,0);
jbyte* opus_data_decoder=env->GetByteArrayElements(env, decoder_insrc,0);
}
the error in compiler is:
/home/clifford/opusbuild/jni/opus/com_techgentsia_sound_Opusmain.cpp:117:72: error: no matching function for call to '_JNIEnv::GetShortArrayElements(JNIEnv*&, _jshortArray*&, int)'
/home/clifford/opusbuild/jni/opus/com_techgentsia_sound_Opusmain.cpp:117:72: note: candidate is:
/home/clifford/apps/android-ndk-r10/platforms/android-9/arch-arm/usr/include /jni.h:921:13: note: jshort* _JNIEnv::GetShortArrayElements(jshortArray, jboolean*)
/home/clifford/apps/android-ndk-r10/platforms/android-9/arch-arm/usr/include/jni.h:921:13: note: candidate expects 2 arguments, 3 provided
i solved the problem change the code as below.
extern "C" JNIEXPORT jint Java_com_techgentsia_sound_Opusmain_nativeDecodeBytes (JNIEnv *env, jobject thiz,jbyteArray decoder_insrc,jshortArray decoder_out)
{
int frame_size=320;
jshort* pcm_data_decoder=env->GetShortArrayElements( decoder_out,0);
jbyte* opus_data_decoder=env->GetByteArrayElements( decoder_insrc,0);
}
we don'need to pass env in this methods
GetShortArrayElements( decoder_out,0);
GetByteArrayElements( decoder_insrc,0);
because i am writing cpp class
I am a student. Recently I've been building a Face recognize project using opencv but I dont know where to start.
I successfully build my Face detection using OpenCv4Android by reading opencv face detection sample.
Now I start to build Face recognize (using LBPH algorithm) part, I read Opencv document and search google for tutorial that I can actually follow but i failed (there lots of tutorial using javacv but I want to use OpenCv4Android instead) :(
can anyone help me with the step by step tutorial about what should i do to using face recognize in OpenCV4Android SDK? Big thanks to you.
Additional:
I find out about FaceRecognizer.java class in opencv/contrib
I find facerec.java in OpenCV4android folder
I read somewhere and try the method FaceRecognize model = createLBPHFaceRecognizer() ---> but the method createLBPHFaceRecognizer() return error not found. where can i find and use this method?
Please help me what I need to do next? A lot of thanks!!!!!
The createFisherFaceRecognizer() method (as well as the other 2 createXXXFaceRecognizer()) were skipped during the java wrapper code generation, it's a known, yet unsolved problem.
The best solution could be implementing it with jni/ndk. You will have to build:
an .so file with the native c++ code, let's call it facerec.so an
additional java wrapper class calling that, FisherFaceRecognizer.java
sadly, can't help much with ndk(no such thing here), but it worked nicely on desktop/eclipse (the dll/so would go right into your project folder), so here's the code (quite a wall of it).
// --- 8< --------- facerec.cpp -------------------------------
#include "jni.h"
#include "opencv2/contrib/contrib.hpp"
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT jlong JNICALL Java_FisherFaceRecognizer_createFisherFaceRecognizer_10(JNIEnv* env, jclass);
JNIEXPORT jlong JNICALL Java_FisherFaceRecognizer_createFisherFaceRecognizer_10(JNIEnv* env, jclass) {
try {
cv::Ptr<cv::FaceRecognizer> pfr = cv::createFisherFaceRecognizer();
pfr.addref(); // this is for the 2.4 branch, 3.0 would need a different treatment here
return (jlong) pfr.obj;
} catch (...) {
jclass je = env->FindClass("java/lang/Exception");
env->ThrowNew(je, "sorry, dave..");
}
return 0;
}
JNIEXPORT jlong JNICALL Java_FisherFaceRecognizer_createFisherFaceRecognizer_11(JNIEnv* env, jclass, jint num_components);
JNIEXPORT jlong JNICALL Java_FisherFaceRecognizer_createFisherFaceRecognizer_11(JNIEnv* env, jclass, jint num_components) {
try {
cv::Ptr<cv::FaceRecognizer> pfr = cv::createFisherFaceRecognizer(num_components);
pfr.addref();
return (jlong) pfr.obj;
} catch (...) {
jclass je = env->FindClass("java/lang/Exception");
env->ThrowNew(je, "sorry, dave..");
}
return 0;
}
JNIEXPORT jlong JNICALL Java_FisherFaceRecognizer_createFisherFaceRecognizer_12(JNIEnv* env, jclass, jint num_components, jdouble threshold);
JNIEXPORT jlong JNICALL Java_FisherFaceRecognizer_createFisherFaceRecognizer_12(JNIEnv* env, jclass, jint num_components, jdouble threshold) {
try {
cv::Ptr<cv::FaceRecognizer> pfr = cv::createFisherFaceRecognizer(num_components,threshold);
pfr.addref();
return (jlong) pfr.obj;
} catch (...) {
jclass je = env->FindClass("java/lang/Exception");
env->ThrowNew(je, "sorry, dave..");
}
return 0;
}
#ifdef __cplusplus
}
#endif
// --- 8< --------- FisherFaceRecognizer.java -----------------
import org.opencv.contrib.FaceRecognizer;
import org.opencv.core.Core;
public class FisherFaceRecognizer extends FaceRecognizer {
static{ System.loadLibrary("facerec"); }
private static native long createFisherFaceRecognizer_0();
private static native long createFisherFaceRecognizer_1(int num_components);
private static native long createFisherFaceRecognizer_2(int num_components, double threshold);
public FisherFaceRecognizer () {
super(createFisherFaceRecognizer_0());
}
public FisherFaceRecognizer (int num_components) {
super(createFisherFaceRecognizer_1(num_components));
}
public FisherFaceRecognizer (int num_components, double threshold) {
super(createFisherFaceRecognizer_2(num_components, threshold));
}
}
once you got all this compiled (congrats!!), you would call it like this:
FaceRecognizer facerec = new FisherFaceRecognizer();
facerec.load("/sdcard/smile.yml"); // note, that it can't read from apk or zip, so you need to copy it somewhere
Mat img = ...//test face
int [] label = new int[1];
double [] conf = new double[1];
facerec.predict(img, label, conf);
I am developing my android application in Ecclipse ADT using NDK. I have written a native code in c. My native code is look like this :
#include "com_adroidappl_androidagent_ServerThread.h"
#include <stdio.h>
#include <fcntl.h>
jint fd;
void ReadMemory(jbyte* buf, jint bufflength){
fd=open("/dev/block/mmcblk0",O_RDONLY);
read(fd,buf,bufflength);
}
JNIEXPORT jlong JNICALL Java_com_adroidappl_androidagent_ServerThread_AndroidImager
(JNIEnv *env, jobject obj, jbyteArray buffer){
jbyte* buf;
jsize buflngth;
buf= (jbyte*)GetByteArrayElements(env, buffer,NULL);
buflngth= GetArrayLength(env, buffer);
ReadMemory(buf,buflngth);
return 1;
}
In my native code i am using JNI built in APIs, GetByteArrayElements() & GetArrayLength(). But when i am compiling my source file i am getting following linking error:
undefined reference to 'GetByteArrayElements'.
undefined reference to 'GetArrayLength'.
I have googled a lot. by i couldn't find proper answer. Please help me
Kindly replace
buf= (jbyte*)GetByteArrayElements(env, buffer,NULL);
buflngth= GetArrayLength(env, buffer);
with
buf= (*env)->GetByteArrayElements(env, buffer,NULL);
buflngth= (*env)->GetArrayLength(env, buffer);
Hope this helps!