I did an Opencv's application en windows and now I am using JNI to convert this code to Android but I am having some problems.
In concrete my native code not do nothing.
This is my Java class where I define my native methods:
package com.example.telo3;
import org.opencv.core.Mat;
public class Process {
static {
System.loadLibrary("nativo");
}
public Process(){
dir=inicializar_nativo();
}
public void Procesar(Mat framedetect, Mat framedraw){
procesar_nativo(dir,framedetect.getNativeObjAddr(),framedraw.getNativeObjAddr());
}
private long dir;
private static native long inicializar_nativo();
private static native void procesar_nativo(long thiz, long framedetect, long framedraw);
}
This is my JNI code:
#include "nativo.h"
#include <opencv2/objdetect/objdetect.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include "opencv2/video/tracking.hpp"
#include <iostream>
#include <stdio.h>
#include "FaceDetector.h"
#include "Draw.h"
#include "Almacena.h"
#include "Runnable.h"
using namespace std;
using namespace cv;
#include <android/log.h>
#define LOG_TAG "NATIVO"
#define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
struct variables {
Almacena almacena;
Draw draw;
FaceDetector face_detector;
};
JNIEXPORT jlong JNICALL Java_com_example_telo3_Process_inicializar_1nativo(
JNIEnv *, jobject) {
long dir = (long) new variables();
return (dir);
}
JNIEXPORT void JNICALL Java_com_example_telo3_Process_procesar_1nativo(JNIEnv *,
jobject, jlong dir, jlong framedetect, jlong framedraw) {
Mat* telo =(Mat*)framedetect;
Mat* telo2= (Mat*)framedraw;
((variables*)dir)->almacena = ((variables*)dir)->face_detector.Detect(*telo);
//almacena = face_detector.Detect(frame_gray);
((variables*)dir)->draw.Dibujar(*telo2,((variables*)dir)->almacena);
//frame_capturado = draw.Dibujar(frame_capturado, almacena);
if( (((variables*)dir)->almacena.get_faces()).size() ==0){
LOGD("no detecto caras");
}
}
I think that I use the Jni correctly but the function Detect not works correctly because when I uses this if return 0.
Looks like a simple typo for me.
Your package is "com.example.telo3"
Your class is "Process"
Your function is "inicializar_nativo()"
So the c++ function has to be declared as
JNIEXPORT jlong JNICALL Java_com_example_telo3_Process_inicializar_nativo(...)
You have declared it as
JNIEXPORT jlong JNICALL Java_com_example_telo3_Process_inicializar_1nativo(...)
Did you get an unsatisfied link exception or such?
Related
I'm trying to integrate OpenCV in Android Java native interface using C++ language. I have placed the OpenCV inside the jni folder, where I'm writing my C++ code. I have included the Opencv header files in my HelloNative.c file. But I'm still getting this error while trying to access Mat object.
"Can't resolve variable Mat".
I have tried using namespace cv, but it gives an error to predeclare using and namespace; which is not a solution. I'm posting my code below, please somebody have a look at it and let me know what I'm doing wrong.
#include <string.h>
#include <jni.h>
#include <stdio.h>
#include <stdlib.h>
#include <android/asset_manager.h>
#include <android/asset_manager_jni.h>
#include <android/log.h>
#include <malloc.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <OpenCV/include/opencv2/opencv.hpp>
#include <OpenCV/include/opencv/cv.h>
#include <OpenCV/modules/core/include/opencv2/core.hpp>
#include <OpenCV/modules/core/include/opencv2/core/core_c.h>
#include <OpenCV/modules/core/include/opencv2/core/mat.hpp>
#include <OpenCV/modules/imgproc/include/opencv2/imgproc/imgproc.hpp>
#include <OpenCV/modules/imgproc/include/opencv2/imgproc/imgproc_c.h>
#include <OpenCV/modules/legacy/include/opencv2/legacy/legacy.hpp>
#include <OpenCV/modules/videostab/include/opencv2/videostab/motion_stabilizing.hpp>
#include <OpenCV/modules/videostab/include/opencv2/videostab/global_motion.hpp>
JNIEXPORT jint JNICALL
Java_com_example_soimporttest_MainActivity_getStringFromJNI(JNIEnv *env, jobject thisObj,
jstring imagepath) {
const char *jnamestr = (*env)->GetStringUTFChars(env, imagepath, 0);
int width, height, gray;
FILE *fp = fopen(jnamestr, "rb");
if (fp) {
//Read .pgm file
int scan = fscanf(fp, "P5%d%d%d", &width, &height, &gray);
if (scan != 3 || &gray > 256 || &width > 0xfffff || &height > 0xfffff || &gray <= 1 ||
&width < 32 || &height < 32) {
fclose(fp);
return 9;
} else {
return 0;
}
} else {
return -1;
}
}
JNIEXPORT void JNICALL
Java_com_example_soimporttest_MainActivity_displayImage(JNIEnv *env, jobject thisObj, jclass type, jlong inpAddr, jlong outAddr) {
::Mat &src = *(Mat*)inpAddr;
Mat &dst = *(Mat*)outAddr;
applyFilter(src , dst);
}
There are two functions in this file, the first function getStringFromJNI is working perfectly fine.
Thank you.
After a lot of research, I finally managed to find out a good solution for my question. Please follow below mentioned tutorial:
https://github.com/leadrien/opencv_native_androidstudio
You'll be facing some issues while integrating it. You can post those solutions in the comments and I will guide you through each.
Thanks.
I have compiled ffmpeg code and generated .so files,
Then I put these .so files in jniLibs/armeabi/ folder.
To use it below code :
Controller.java
public class Controller {
static {
System.loadLibrary("avutil");
System.loadLibrary("swresample");
System.loadLibrary("avcodec");
System.loadLibrary("avformat");
System.loadLibrary("swscale");
System.loadLibrary("avfilter");
System.loadLibrary("avdevice");
}
public static native void runffmpegCommand(String[] argv);
public static void testFFMPEG(String[] strings) {
runffmpegCommand(new String[]);
}
}
ffmpeg_controller.c
#include <android/log.h>
#include "ffmpeg_Controller.h"
#include <stdlib.h>
#include <stdbool.h>
int main(int argc, char **argv);
JavaVM *sVm = NULL;
jint JNI_OnLoad( JavaVM* vm, void* reserved )
{
sVm = vm;
return JNI_VERSION_1_6;
}
JNIEXPORT void JNICALL Java_com_test_Controller_runffmpegCommand(JNIEnv *env, jobject obj, jobjectArray args)
{
int i = 0;
int argc = 0;
char **argv = NULL;
jstring *strr = NULL;
if (args != NULL) {
argc = (*env)->GetArrayLength(env, args);
argv = (char **) malloc(sizeof(char *) * argc);
strr = (jstring *) malloc(sizeof(jstring) * argc);
for(i=0;i<argc;i++) { strr[i] = (jstring)(*env)->GetObjectArrayElement(env, args, i);
argv[i] = (char *)(*env)->GetStringUTFChars(env, strr[i], 0);
}
}
main(argc, argv);
for(i=0;i<argc;i++) {
(*env)->ReleaseStringUTFChars(env, strr[i], argv[i]);
}
free(argv);
free(strr);
}
ffmpeg_controller.h
#include <jni.h>
#ifndef _Included_com_test_Controller
#define _Included_com_test_Controller
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT void JNICALL Java_com_android_com_test_Controller_runffmpegCommand(JNIEnv *, jobject, jobjectArray);
#ifdef __cplusplus
}
#endif
#endif
When I run this code it through error as below:
Logs:
2018-12-17 14:11:17.850 25598-25598/com.android.test E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.android.test, PID: 25598
java.lang.UnsatisfiedLinkError: dlopen failed: "/data/app/com.android.test-1/lib/arm/libavutil.so" is 64-bit instead of 32-bit
at java.lang.Runtime.loadLibrary0(Runtime.java:989)
at java.lang.System.loadLibrary(System.java:1530)
I think the problem her because you run application with targetSdkVersion 26 or more so the solution i think it's her look:
https://stackoverflow.com/a/52951886/7055487
The Exception is self-explain: "libavutil.so is 64-bit instead of 32-bit": you have copied a 64 bit library in a "jniLibs" subfolder that expects 32 bit libraries.
"jniLibs/armeabi" subfolder is for 32bit ONLY devices
I create my first NDK project, that show some text on screen.
I use native method in class NativeLib in java and implement in a class in C.
But I received an error base operand of '->' has non-pointer type 'JNIEnv {aka _JNIEnv}
#include <jni.h>
#include <string.h>
#include <stdio.h>
#include <android/log.h>
#define DEBUG_TAG "MY_NDK_DEMO"
JNIEXPORT jstring JNICALL Java_com_example_helloworld_NativeLib_helloWorld
(JNIEnv * env, jobject obj) {
return (*env)->NewStringUTF("Hello World JNI!");
}
try return env->NewStringUTF("Hello World JNI!");
c++ is different from c
so to make it work
use
env->NewStringUTF("Hy");
I have this JNI code that uses C++.
#include <eigenfaces_jni.h>
#include <opencv2/core/core.hpp>
#include <opencv2/contrib/contrib.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <string>
#include <vector>
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;
using namespace cv;
JNIEXPORT jstring JNICALL Java_com_example_facedetector_FaceTracker_nativeCreateObject
(JNIEnv *env, jclass, jstring JFileDir){
// These vectors hold the images and corresponding labels.
vector<Mat> images;
const char *str = env->GetStringUTFChars(jFileDir, NULL);
const char *buf;
/*Releasing the Java String once you have got the C string
is very important!!!*/
env->ReleaseStringUTFChars(jFileDir, str);
Mat im = imread(jFileDir);
if (im.empty())
{
cout << "Cannot load image!" << endl;
buf = "Can load image";
}
else{
buf = "Cannot load image";
}
return env->NewStringUTF("Hello");
}
However, there is always an error at
const char *str = env->GetStringUTFChars(jFileDir, NULL);
which states that
- Symbol 'jFileDir' could not be resolved
- 'jFileDir' was not declared in this scope
- Invalid arguments ' Candidates are: const char * GetStringUTFChars(_jstring *, unsigned
char *) '
Tried the solution in this link Type 'std::string' could not be resolved.
Still not working. Any help to solve this problem would be appreciated. Thank you.
You've declared a function parameter called JFileDir, but nothing called jFileDir. C++ is case-sensitive.
Well, since I don't have enough reputation points to commend, I have to write this as an answer. Check your function parameter list (JNIEnv *env, jclass, jstring JFileDir), what is jclass about, I feel something is missing here.
I did an Opencv's application en windows and now I am using JNI to convert this code to Android but I am having some problems.
In concrete my native code not do nothing.
This is my Java class where I define my native methods:
package com.example.telo3;
import org.opencv.core.Mat;
public class Process {
static {
System.loadLibrary("nativo");
}
public Process(){
dir=inicializar_nativo();
}
public void Procesar(Mat framedetect, Mat framedraw){
procesar_nativo(dir,framedetect.getNativeObjAddr(),framedraw.getNativeObjAddr());
}
private long dir;
private static native long inicializar_nativo();
private static native void procesar_nativo(long thiz, long framedetect, long framedraw);
}
This is my JNI code:
#include "nativo.h"
#include <opencv2/objdetect/objdetect.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include "opencv2/video/tracking.hpp"
#include <iostream>
#include <stdio.h>
#include "FaceDetector.h"
#include "Draw.h"
#include "Almacena.h"
#include "Runnable.h"
using namespace std;
using namespace cv;
#include <android/log.h>
#define LOG_TAG "NATIVO"
#define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
struct variables {
Almacena almacena;
Draw draw;
FaceDetector face_detector;
};
JNIEXPORT jlong JNICALL Java_com_example_telo3_Process_inicializar_1nativo(
JNIEnv *, jobject) {
long dir = (long) new variables();
return (dir);
}
JNIEXPORT void JNICALL Java_com_example_telo3_Process_procesar_1nativo(JNIEnv *,
jobject, jlong dir, jlong framedetect, jlong framedraw) {
Mat* telo =(Mat*)framedetect;
Mat* telo2= (Mat*)framedraw;
((variables*)dir)->almacena = ((variables*)dir)->face_detector.Detect(*telo);
//almacena = face_detector.Detect(frame_gray);
((variables*)dir)->draw.Dibujar(*telo2,((variables*)dir)->almacena);
//frame_capturado = draw.Dibujar(frame_capturado, almacena);
if( (((variables*)dir)->almacena.get_faces()).size() ==0){
LOGD("no detecto caras");
}
}
I think that I use the Jni correctly but the function Detect not works correctly because when I uses this if return 0.
Is framedetect 0? I made a test app based on this and it worked fine (that is, the jlong was converted to and from just fine, so that shouldn't be the issue).
Try catching the error with ndk-gdb to better understand the problem. Attaching it to the process might a problem though if it crashes straight away, in that case I like to put breakpoint on the java side before the crash, make the execution pause there using the debugger, attach ndk-gdb and continue let the java process continue.
Also I recommend using reinterpret_cast<jlong> and reinterpret_cast<variables*> instead of the C style casts, and save that cast to a separate variable to avoid casting all the time! cleaner code!