Face recognize using Opencv4Android SDK tutorial? - android

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);

Related

Change function name in a .so library

I only have 1 .so file from old project.
How can I use this file without creating the same package in project or module ?
Actually, you don't need to change function name in .so file. You can use dlopen to load your .so library dynamically at runtime and dlsym to get pointer for you YOUR_FUNCTION_NAME() and then call YOUR_FUNCTION_NAME() by pointer. For do that in your current project you can create "wrapper" like that:
public class OldSoHelper {
public static native void loadOldSo();
public static native <TYPE_OF_RESULT> runFunFromOldSo(<PARAMETERS>);
public static native void unloadOldSo();
}
and in corresponding .c/.cpp file of current project (e.g. native-lib.cpp by default):
void *handle;
<TYPE_OF_OLD_FUNCTION> (*old_fun_wrapper)(<PARAMETERS_OF_OLD_FUNCTION>);
extern "C"
JNIEXPORT void JNICALL
Java_<YOUR_PACKAGE_NAME>_OldSoHelper_loadOldSo(JNIEnv *env, jclass type) {
handle = dlopen("<YOUR_OLD_SO>.so", RTLD_NOW);
old_fun_wrapper = (<TYPE_OF_OLD_FUNCTION> (*)(<PARAMETERS_OF_OLD_FUNCTION>))(dlsym(handle, "<OLD_FUNCTION_NAME_e.g._Java_com_abc_dee_Native_appInit>"));
}
extern "C"
JNIEXPORT jobject JNICALL
Java_<YOUR_PACKAGE_NAME>_OldSoHelper_runFunFromOldSo(JNIEnv *env, jclass type,
<PARAMETERS_FOR_OLD_FUNCTION>)
{
jclass ResultClass = env->FindClass("YOUR/PACKAGE/NAME/RESULT_CLASS");
jobject result = ...
jfieldID fieldId = env->GetFieldID(ResultClass, "<FIELD_NAME>", "<FILED_TYPE_LETTER>");
<TYPE_OF_OLD_FUNCTION> res = old_fun_wrapper(<PARAMETERS_FOR_OLD_FUNCTION>);
env->Set<TYPE>Field(result, fieldId , res.filed);
return result;
}
extern "C"
JNIEXPORT void JNICALL
Java_<YOUR_PACKAGE_NAME>_OldSoHelper_unloadOldSo(JNIEnv *env, jclass type) {
if (handle) {
dlclose(handle);
}
}
and from java code you can call:
...
// when you need old .so e.g. in onCreate()
OldSoHelper.loadOldSo();
...
// when you no need to call function from old .so
<TYPE_OF_RESULT> result = OldSoHelper.runFunFromOldSo(<PARAMETERS>);
...
// when you no need old .so e.g. in onDestroy()
OldSoHelper.unloadOldSo();
...

How to call JNI Function from a method in C library

I'm currently developping an android app with android studio, for this project i need to use a custom library written in c/c++ .
So i in order to do that i needed to use NDK.
The library contain methods that i need to implements in order to have access to specifics fonctions in android
My question is : how can I call my jni method inside the method existing in c
which will call a java method to store session key in the android system
So for a pratical exemple since it's maybe not clear:
In a file called lib_exemple.c i have three methods
the first one is the initialisation call to the library (jni to library c) -->working
JNIEXPORT void JNICALL
Java_com_example_libExemple_Libs_ExempleLib_lib_1Exemple_1init
(JNIEnv *env, jobject instance) {
lib_Example_init('0'); // c func of the library
}
then the second one is the jni who call a java method (jni to java) -> working
JNIEXPORT jint
JNICALL Java_com_example_libExemple_Libs_ExempleLib_lib_1Exemple_1store_1session_1key
(JNIEnv * env, jobject jobject1, jbyte jbyte1, jchar jchar1, jbyte jbyte2){
jclass clazz = (*env)->FindClass(env, "com/example/libExemple/Libs/ExempleLib");
jmethodID mCurrentActivityId = (*env)->GetMethodID(env, clazz, "KeyStoreSessionKey", "(BCB)I");
jint result = (*env)->CallIntMethod(env, jobject1, mCurrentActivityId, jbyte1, jchar1, jbyte2);
return result;
}
and the third method is the one the library c have in it (library C to jni)
int lib_Exemple_store_session_key(uint8_t Session, P_KEY_ST_T pKey, uint8_t keyType) {
//i want to call jni func here , so the librairy can access the native android function
return 0;
}
then to configure the ndk in a file called ExempleLib.java i have defined
static {
System.loadLibrary("LibExemple");
}
then the prototype of the initialisation of the library
public native void libExemple_init();
the prototype of the first method in lib_exemple.c
public native int lib_Exemple_store_session_key(byte pKey, char key_length, byte keyIndex);
and the java fonction called by it
protected int KeyStoreSessionKey(byte pKey, char key_length, byte keyIndex) {
...
}
my mainActivity contain
ExempleLib LibFunc = new ExempleLib();
Log.d(TAG, "init lib" );
LibFunc.lib_Exemple_init();
My goal is that after initialising my library and call an init function , it can call the first method in the second method of lib_exemple.c (the one used in the library )
thanks
EDIT :
The solution of my problem is when i initialize the lib , i need to save jvm
so i can access the JNIenv in the library method directly
jobject Savedinstance = NULL;
static JavaVM *cachedJVM;
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
cachedJVM = jvm;
return JNI_VERSION_1_6;
}
JNIEnv *AttachJava() {
JavaVMAttachArgs args = {JNI_VERSION_1_6, 0, 0};
JNIEnv *java;
(*cachedJVM)->AttachCurrentThread(cachedJVM, &java, &args);
return java;
}
JNIEXPORT jint JNICALL
Java_com_example_vgosselin_libExemple_Libs_ExempleLib_lib_1init(JNIEnv *env,
jobject instance) {
Savedinstance = instance;
void *element = 0;
jint result;
result = lib_Exemple_init_();
return result;
}
so i can call the java method in
int lib_Exemple_store_session_key(uint8_t Session, P_KEY_ST_T pKey, uint8_t keyType) {
JNIEnv *NewEnv = AttachJava();
jclass clazz = (*NewEnv)->FindClass(NewEnv,"com/example/vgosselin/libExemple/Libs/ExempleLib");
jmethodID mCurrentActivityId = (*NewEnv)->GetMethodID(NewEnv,clazz,"KeystoreStoreKey","([BCB)I");
jint result;
jbyteArray Data = 0;
jchar Key = 0;
jbyte Type = 0;
result = (*NewEnv)->CallIntMethod(NewEnv, Savedinstance, mCurrentActivityId, Data, Key, Type);
return result;
}
and now i don't need the method in jni syntax anymore
JNIEXPORT jint JNICALL Java_com_example_libExemple_Libs_ExempleLib_lib_1Exemple_1store_1session_1key

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
}

Android calling functions in a shared library

I am trying to follow this tutorial
http://www3.ntu.edu.sg/home/ehchua/programming/java/JavaNativeInterface.html
but I'm in eclipse making an android app
So I create blank project and add a new class
package com.example.jpgtest;
import android.util.Log;
public class TestJNIPrimitive {
//static {
//System.loadLibrary("myjni"); // myjni.dll (Windows) or libmyjni.so (Unixes)
// System.load("d:/libjpeg.so");
// Log.d("TestJNIPrimitive", "load ok");
// }
// Declare a native method average() that receives two ints and return a double containing the average
private native double average(int n1, int n2);
// Test Driver
public static void main() {
System.load("d:/libjpeg.so");
Log.d("TestJNIPrimitive", "load ok");
double d = new TestJNIPrimitive().average(3, 2);
//double d = new TestJNIPrimitive().average(3, 2);
Log.d("TestJNIPrimitive", "d="+d);
}
}
and call it from onCreate()
TestJNIPrimitive t = new TestJNIPrimitive();
t.main();
I made the c and h file like this
TestJNIPrimitive.h
/
* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class TestJNIPrimitive */
#ifndef _Included_TestJNIPrimitive
#define _Included_TestJNIPrimitive
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: TestJNIPrimitive
* Method: average
* Signature: (II)D
*/
JNIEXPORT jdouble JNICALL Java_TestJNIPrimitive_average
(JNIEnv *, jobject, jint, jint);
#ifdef __cplusplus
}
#endif
#endif
TestJNIPrimitive.c
#include <jni.h>
#include "TestJNIPrimitive.h"
JNIEXPORT jdouble JNICALL Java_TestJNIPrimitive_average(JNIEnv *env, jobject thisObj, jint n1, jint n2)
{
jdouble result;
//printf("In C, the numbers are %d and %d\n", n1, n2);
result = ((jdouble)n1 + n2) / 2.0;
// jint is mapped to int, jdouble is mapped to double
return result;
}
i build it and make a libjpg.so on my d drive root
i check the symbols
$ readelf -Ws /cygdrive/d/libjpeg.so | grep average
272: 00003f5c 72 FUNC GLOBAL DEFAULT 7 Java_TestJNIPrimitive_average
1896: 00003f5c 72 FUNC GLOBAL DEFAULT 7 Java_TestJNIPrimitive_average
When I run it, the load works ok but the call to average fails with
No implementation found for native Lcom/example/jpegtest/TestJNIPrimative;.average (II)D
Any ideas please, I'm really stuck on this
Thanks
You are missing the packace into JNI. That's the reason the function is not found.
Your Java package is: com.example.jpgtest
So your Native function must be:
JNIEXPORT jdouble JNICALL Java_com_example_jpgtest_TestJNIPrimitive_average(JNIEnv *env, jobject thisObj, jint n1, jint n2)
{
...
}
After compile with ndk-build, and use your new libjpeg.so must work.
I have to add that your java looks weird (at less to my eyes). I will implement that as:
package com.example.jpgtest;
import android.util.Log;
public class TestJNIPrimitive
{
// Test Driver
public static void main()
{
Log.d("TestJNIPrimitive", "load ok");
double d = new TestJNIPrimitive().average(3, 2);
Log.d("TestJNIPrimitive", "d="+d);
}
// Native functions (Callbacks from Java to C++)
// =========================================================================
// Declare a native method average() that receives two ints and return a double containing the average
private native double average(int n1, int n2);
// Load Native Libraries
// =========================================================================
static
{
System.load("libjpeg.so");
}
}
And the so must be inside folder libs/armeabi-v7a
I you want a basic theory check this or the specifications
i was unable to figure out the problem, but instead i read this
https://developer.android.com/tools/sdk/ndk/index.html
i build and ran the hello-jni example and then i build a new project and then added in the jni folder from the test and change the package name and the class name to match the new project
then i started modifying the functions to my needs and its ok now
not easy stuff this

UnsatisfiedLinkError: Native method not found - Android

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

Categories

Resources