Android NDK passing parameters to native methods - android

I am studying OpenCV4Android SDK, in the 2.4.5 version, with the NDK framework, using which I can use native code (written in C/C++) in the Android environment. But I don't exactly understand how parameters are passed from Android to C.
For example, in the 'mixedprocessing' sample, in the directory 'jni' there's a .cpp file named 'jni_part', whose code is:
#include <jni.h>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <vector>
using namespace std;
using namespace cv;
extern "C" {
JNIEXPORT void JNICALL Java_org_opencv_samples_tutorial2_Tutorial2Activity_FindFeatures(JNIEnv*, jobject, jlong addrGray, jlong addrRgba);
JNIEXPORT void JNICALL Java_org_opencv_samples_tutorial2_Tutorial2Activity_FindFeatures(JNIEnv*, jobject, jlong addrGray, jlong addrRgba) {
Mat& mGr = *(Mat*)addrGray;
Mat& mRgb = *(Mat*)addrRgba;
vector<KeyPoint> v;
FastFeatureDetector detector(50);
detector.detect(mGr, v);
for( unsigned int i = 0; i < v.size(); i++ ) {
const KeyPoint& kp = v[i];
circle(mRgb, Point(kp.pt.x, kp.pt.y), 10, Scalar(255,0,0,255));
}
}
}
In the MainActivity there's the method:
public native void FindFeatures(long matAddrGr, long matAddrRgba);
So it's passed as parameter the native address of a Mat object, but how does it become a matrix in C?
And which features are detected from a FastFeatureDetector object?

FindFeatures, in Java, calls its exact equivalent in C/C++:
JNIEXPORT void JNICALL Java_org_opencv_samples_tutorial2_Tutorial2Activity_FindFeatures(JNIEnv*, jobject, jlong addrGray, jlong addrRgba){
Mat& mGr = *(Mat*)addrGray;
Mat& mRgb = *(Mat*)addrRgba;
...
This is where it becomes a cv::Mat. (Mat*) casts what is pointed by address addrGray (respectively addrRgba) to a "pointer to a cv::Mat". Then, the value pointed by this newly created pointer is put in mGr (respectively mRgb), which is a cv::Mat.
In other words, you only give to C/C++ an address in the memory, and you have to make sure that what's there actually is a valid cv::Mat.
About your second question, the FAST detector detects points of interest in the image (i.e. points that contain a lot of information). The idea is to be able to identify those points on multiple different images. To simplify, you can consider a feature detected by FAST as a corner in the image.

Related

Android ndk undefined reference error

I have a C++ source file, and I want to call a method from my C++ file, but I dont know whats wrong.
Here is my cpp method:
static unsigned ALawEncode(uint8_t* dst, int16_t* src, size_t srcSize);
Here is where I would like to call my method:
#include <string.h>
#include <jni.h>
#include <stdint.h>
#include "G711.h"
extern "C" {
uint8_t* Java_com_example_qonclient_Codecs_encodeG711( JNIEnv* env, jobject thiz, int16_t* source ){
size_t size0 = sizeof(source);
G711 g711;
uint8_t *dst;
g711.ALawEncode(dst, source, size0);
return dst;
}
}
Could you help me?

Field 'distance' could not be resolved when using OpenCV4Android

I was tring to use ORB feature in Android apps,and create a project.When I use BruteForceMatcher and write the code:dist=matches[i].distance, My IDE notice me that "Field 'distance' could not be resolved". Why this happened?
#include <jni.h>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/legacy/legacy.hpp>
#include <iostream>
#include <vector>
using namespace std;
using namespace cv;
extern "C" {
JNIEXPORT int JNICALL Java_org_opencv_samples_tutorial2_Tuturial2Activity_CompareFeatures(JNIEnv*, jobject, jlong addrGray, jlong addrRgba);
JNIEXPORT int JNICALL Java_org_opencv_samples_tutorial2_Tuturial2Activity_CompareFeatures(JNIEnv*, jobject, jlong addrGray, jlong addrRgba)
{
char img_filename1[]="/sdcard/src.jpg";
char img_filename2[]="/sdcard/demo.jpg";
Mat src1,src2;
src1=imread(img_filename1,CV_LOAD_IMAGE_GRAYSCALE);
src2=imread(img_filename2,CV_LOAD_IMAGE_GRAYSCALE);
ORB orb;
vector<KeyPoint> keys1,keys2;
Mat descriptors1,descriptors2;
orb(src1,Mat(),keys1,descriptors1);
orb(src2,Mat(),keys2,descriptors2);
BruteForceMatcher<HammingLUT> matcher;
vector<DMatch> matches;
matcher.match(descriptors1,descriptors2,matches);
double max_dist=0; double min_dist=255;
//--Quick calculation of max and min distances between keypoints
for (int i=0;i<descriptors1.rows;i++)
{
double dist=matches[i].distance;
}
return 0;
}
}
Goto Project Properties -> C/C++ General -> GNU C++ ->
Edit change 4.x to 4.4.3 in ${NDKROOT}/sources/cxx-stl/gnu-libstdc++/4.x....

Use a simple c++ class in Android NDK

I'm trying to learn the basics of Android NDK but I'm stucked when I have to use it with a c++ class.
I understand how to use it with a simple function but what should I do to be able to manipulate the fields and the methods of a c++ class ?
I'm trying to do it with this simple c++ class :
#include <cstdlib>
#include <jni.h>
using namespace std;
class Point {
int x, y; // coordonnées du point
public:
Point() {
this->x = 0;
this->y = 0;
}
Point(int x, int y) {
this->x = x;
this->y = y;
}
int getX() const {
return x;
}
int getY() const {
return y;
}
Point symetrique() const {
return Point(-x, -y);
}
bool operator ==(const Point &p) const {
return this->x == p.getX() && this->y == p.getY();
}
};
extern "C" {
JNIEXPORT jlong JNICALL Java_com_example_jnipoint_JPoint_createPoint__
(JNIEnv *, jobject);
JNIEXPORT jlong JNICALL Java_com_example_jnipoint_JPoint_createPoint__II
(JNIEnv *, jobject, jint, jint);
JNIEXPORT jint JNICALL Java_com_example_jnipoint_JPoint_nativeGetX
(JNIEnv *, jobject, jlong);
JNIEXPORT jint JNICALL Java_com_example_jnipoint_JPoint_nativeGetY
(JNIEnv *, jobject, jlong);
JNIEXPORT jlong JNICALL Java_com_example_jnipoint_JPoint_nativeSymetrique
(JNIEnv *, jobject, jlong);
};
JNIEXPORT jlong JNICALL Java_com_example_jnipoint_JPoint_createPoint__(JNIEnv* env, jobject thiz) {
return (jlong)(new Point());
}
JNIEXPORT jlong JNICALL Java_com_example_jnipoint_JPoint_createPoint__II(JNIEnv* env, jobject thiz, jint x, jint y) {
return (jlong)(new Point(x, y));
}
JNIEXPORT jint JNICALL Java_com_example_jnipoint_JPoint_nativeGetX(JNIEnv* env, jobject thiz, jlong nativePointer) {
return ((Point*)nativePointer)->getX();
}
JNIEXPORT jint JNICALL Java_com_example_jnipoint_JPoint_nativeGetY(JNIEnv* env, jobject thiz, jlong nativePointer) {
return ((Point*)nativePointer)->getY();
}
jlong Java_com_example_jnipoint_JPoint_nativeSymetrique(JNIEnv* env, jobject thiz, jlong nativePointer) {
return ((Point*)nativePointer)->symetrique();
}
I tried to find samples but nothing so far... Maybe I'm not using the right keywords
* UPDATE *
I created a Java wrapper for the c++ Point class and added to the c++ file JNI methods. The code is the following :
public class JPoint {
private long nativePointer;
public JPoint() {
nativePointer = createPoint();
}
public JPoint(int x, int y) {
nativePointer = createPoint(x, y);
}
public int getX() {
return nativeGetX(nativePointer);
}
public int getY() {
return nativeGetY(nativePointer);
}
public JPoint symetrique() {
JPoint tmp = new JPoint();
tmp.nativePointer = nativeSymetrique(nativePointer);
return tmp;
}
// TODO
/*public boolean equals(Object o) {
return nativeEquals(o);
}*/
private native long createPoint(); // Void constructor
private native long createPoint(int x, int y);
private native int nativeGetX(long nativePointer);
private native int nativeGetY(long nativePointer);
private native long nativeSymetrique(long nativePointer);
//private native boolean nativeEquals(Object p); TODO
}
Right now I'm stucked with the nativeSymetrique function, it says that I cannot convert 'Point' to 'jlong'. Can anyone help me on this ? Thanks
* UPDATE 2 *
SWIG solved my issues, you don't have to handwrite the wrappers and it seems to be a good choice for big libraries.
Have a look at JNA.
JNI is meant to access Java classes/objects from C. Which means that JNI gives you C functions for accessing JVM. But there is no way vice versa: to access C structures (C++ classes) from JVM. Java has no such methods. So if you want to have a "class reflection" between C++ and Java, the only you can do is to have the class on Java side and a set of JNI C calls to access, modify and call methods on the Java object. JNI native methods on Java side are of no use for you, because the only parameters it can take (in or out) can be again only Java objects (or primitives or arrays). There is simply no way to pass C(++) structures/objects to Java side.
You can manipulate with your C code as you wish and pass\return values via JNI, you can find JNI samples in androidndk/samples - helloJni.
For example:
JNIEXPORT jfloat JNICALL Java_com_opengl_glworld_GLWorldRenderer_changeCurrentArea(JNIEnv *env, jobject obj, jfloat curArea)
{
area = curArea;
return area;
// here you can execude you C code, you can access to methods of class,
// or method that use your classes.
}
As I said in my second update, SWIG was the perfect match for my needs.

how to generate random number jni in android

hi I m trying to convert my java code to c code for better speed ,
and I want to generate a random number in c code using jni(android)
in java code,
public int getRandomNumberFor()
{
Random random ;
random = new Random();
return random.nextInt(0xFF);
}
I don't know what code work for c
I tried finding example, but unfortunately I don't get it. can any one help me in this.?
Change your code as using C Programming in NDK :
#include <stdio.h>
#include <stdlib.h>
JNIEXPORT jint JNICALL Java_com_imrantestndk_androiddemo_NativeLib_Randomnum
(JNIEnv * env, jobject this){
int n;
n = rand()%100 + 1;
return n;
}
Or
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
JNIEXPORT jint JNICALL Java_com_imrantestndk_androiddemo_NativeLib_Randomnum
(JNIEnv * env, jobject this){
int random;
randomize();
random = random(100);
return random;
}

C++ and JNI - How to pass an array into a jfloatArray

I have been messing with my own little project to teach myself the android ndk using c++ and jni but I can't figure out how to pass the data from a java float array to the c++ array. I have used the jni set up. Most the tutorials I find are either too simple and don't explain enough or are too complicated and go over my understanding at the moment. So, can some one just point me to a simple example of an array being passed from java to c++, then have some method/function performed on the data and sent back to java.
Heres my attempt so far but I have two errors left in the way. Im not sure if the rest of the syntax is up to par either but I don't see anything at compile time.
#include <iostream>
#include <Eigen/Dense>
#include <math.h>
#include <jni.h>
using namespace Eigen;
Vector3f vec;
Vector3f vec2;
Vector3f vecRtrn;
void vecLoad(float x, float y, float z, float x2, float y2, float z2){
vec(0) = x;
vec(1) = y;
vec(2) = z;
vec2(0) = x2;
vec2(1) = y2;
vec2(2) = z2;
}
void vecAdd(Vector3f vecA, Vector3f vecB){
vecRtrn = vecA+vecB;
}
extern "C"
{
JNIEXPORT jfloatArray JNICALL Java_jnimath_act_JnimathActivity_test
(JNIEnv *env, jobject obj, jfloatArray fltarray1, jfloatArray fltarray2){
float array1[3];
jfloatArray flt1 = fltarray1;
jfloatArray flt2 = fltarray2;
//flt1 = env->GetFloatArrayElements( fltarray1,0);
//flt2 = env->GetFloatArrayElements( fltarray2,0);
vecLoad(flt1[0], flt1[1], flt1[2], flt2[0], flt2[1], flt2[2]);
vecAdd(vec, vec2);
array1[0] = vecRtrn[0];
array1[1] = vecRtrn[1];
array1[2] = vecRtrn[2];
return array1;
};
}
And these are the errors at compile time
$ /cygdrive/c/android-ndk-r7/ndk-build
Compile++ thumb : test <= test.cpp
jni/test.cpp: In function '_jfloatArray* Java_jnimath_act_JnimathActivity_test(JNIEnv*, _jobject*, _jfloatArray*, _jfloatArray*)':
jni/test.cpp:42: error: cannot convert '_jfloatArray' to 'float' for argument '1' to 'void vecLoad(float, float, float, float, float, float)'
jni/test.cpp:49: error: cannot convert 'float*' to '_jfloatArray*' in return
make: *** [obj/local/armeabi/objs/test/test.o] Error 1
First you can't use jfloatArray directly. Instead, you should do this
JNIEXPORT jfloatArray JNICALL Java_jnimath_act_JnimathActivity_test
(JNIEnv *env, jobject obj, jfloatArray fltarray1, jfloatArray fltarray2)
{
jfloatArray result;
result = env->NewFloatArray(3);
if (result == NULL) {
return NULL; /* out of memory error thrown */
}
jfloat array1[3];
jfloat* flt1 = env->GetFloatArrayElements( fltarray1,0);
jfloat* flt2 = env->GetFloatArrayElements( fltarray2,0);
vecLoad(flt1[0], flt1[1], flt1[2], flt2[0], flt2[1], flt2[2]);
vecAdd(vec, vec2);
array1[0] = vecRtrn[0];
array1[1] = vecRtrn[1];
array1[2] = vecRtrn[2];
env->ReleaseFloatArrayElements(fltarray1, flt1, 0);
env->ReleaseFloatArrayElements(fltarray2, flt2, 0);
env->SetFloatArrayRegion(result, 0, 3, array1);
return result;
}
Please use this as a tutorial and study more. As I said before, studying will help you more than practicing at this time.
This is basically enough for create an empty array with new ndks. Assuming env is your jni environment.
jfloatArray jArray = env -> NewFloatArray(8);
validateAudio(JNIEnv* env, jobject obj, jstring resourceFolderPath, ,jfloatArray thresholdArray){
const char *resource_folder_path = (*env)->GetStringUTFChars(env,resourceFolderPath,0); // string parameter
const jfloat* threshold_array = (*env)->GetFloatArrayElements(env, thresholdArray,0); //float array
}
Instead the older style (above Tae-Sung Shin's code, still works), we should do this nowadays:
jfloatArray result;
result = (*env)->NewFloatArray( env, numbers_here );

Categories

Resources