Java calls C ++ methods with JNI - java

I want to implement image mosaicking with Java call C++ and This is my Java code
package com.example.jni;
public class JNITest {
static {
System.loadLibrary("ConsoleApplication123");
}
// native method : the floder url that has pictures to be mosaic
public native String hello(String name);
}
I compile it to JNITest.h and in this way I pass a folder rul there have photos,
And then in c + + carry on image splicing.but i do not konw how to read these photos in this folder.If I can read these pictures,I can implement image mosaicking,and finaly I want to return the new foler url that has the mosaicked picturess and this is my image_mosaicking.cpp
/* DO NOT EDIT THIS FILE - it is machine generated */
#include "jni.h"
#include <iostream>
#include <fstream>
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/stitching/stitching.hpp"
using namespace std;
using namespace cv;
bool try_use_gpu = true; //false;
vector<Mat> imgs;
string result_name = "result.jpg";
/* Header for class com_example_jni_JNITest */
#ifndef _Included_com_example_jni_JNITest
#define _Included_com_example_jni_JNITest
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_example_jni_JNITest
* Method: hello
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_example_jni_JNITest_hello
(JNIEnv *env, jobject, jstring path) {
//read the path of this folder
const char* temp_path = env->GetStringUTFChars(path, false);
int numberOfPics = 0;
string pics[100];
//how to get the number of pictures in this folder
//how to get every picture's name into pics[]
for (int i = 1; i < numberOfPics; ++i) {
Mat img = imread(pics[i]); //read every pictures in this folder
if (img.empty()) {
cout << "Can't read image '" << argv[i] << "'\n";
// return null;
}
imgs.push_back(img);
}
Mat pano;
Stitcher stitcher = Stitcher::createDefault(try_use_gpu);
Stitcher::Status status = stitcher.stitch(imgs, pano);
if (status != Stitcher::OK) {
cout << "Can't stitch images, error code = " << int(status) << endl;
// retrun null;
}
imwrite(result_name, pano);
imshow("show", pano);
cv::waitKey(0);
jclass strClass = env->FindClass("Ljava/lang/String;");
jstring imgName = env->NewStringUTF(temp_path);
//rteurn the new folder that has mosaicked pictures
}
#ifdef __cplusplus
}
#endif
#endif

Related

getting 'UnsatisfiedLinkError' using JNI to pass string from C++ to java w/OpenCV

The picture linked below shows the specific exception I'm getting. I'm not quite sure why I'm having this particular issue as I've built everything in the same directory, so the library file is there. From what I understand this has something to do with what I'm returning to my main method from my c++ function.
What I'm essentially trying to do is pass the name (printId) of the recognized person, as a string, from my c++ function to java.
Picture of command line:
Here's my C++ code:
#include <jni.h>
#include <iostream>
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/core/core.hpp"
#include "opencv2/opencv.hpp"
#include "opencv2/objdetect.hpp"
#include "opencv2/face.hpp"
#include "opencv2/face/facerec.hpp"
#include <vector>
#include <string>
#include "recognitionJNI.h"
#include <fstream>
#include <sstream>
using namespace cv;
using namespace std;
String face_cascade_name = "/Users/greg/Downloads/opencv-3.4.2/data/haarcascades/haarcascade_frontalface_alt.xml";
CascadeClassifier face_cascade;
String fn_csv = "/Users/greg/Desktop/faceBuild/faceRecognition/faceRecognition/csv.txt";
//User Defined Function for reading csv
static void read_csv(const string& filename, vector<Mat>& images, vector<int>& labels, char separator = ';') {
ifstream file(filename.c_str(), ifstream::in); //opens file for reading
if(!file) {
cout << "ERROR: There was a problem loading the csv file" << endl;
}
string line, path, classlabel;
while(getline(file,line)) {
stringstream liness(line);
getline(liness, path, separator); //read stream object up to the semicolon
getline(liness, classlabel); //read the rest of stream object up to null terminated character
//make sure that the filepath and userID are not empty
if(!path.empty() && !classlabel.empty()) {
images.push_back(imread(path,0)); //appends grayscale image to images vector
labels.push_back(atoi(classlabel.c_str())); //appends userID to labels vector
}
}
}
JNIEXPORT jstring JNICALL Java_testJNIString_userName(JNIEnv *env, jobject thisObj, jstring inJNIStr) {
const char *inCStr = env->GetStringUTFChars(inJNIStr, NULL);
if (NULL == inCStr) return NULL;
string outCppStr;
cout << "In C++, the received string is: " << inCStr << endl;
env->ReleaseStringUTFChars(inJNIStr, inCStr);
string printId;
vector<Mat> images; //This vector will hold the images
vector<int> labels; //This vector will hold the userID
//read the csv file contain image paths and userID's
try {
read_csv(fn_csv, images, labels);
} catch (Exception& e) {
cerr << "Error opening file\"" << fn_csv << "\". Reason: " << e.msg << endl;
exit(1);
}
//we'll need to resize the images to their origal size
//These two lines capture the length and width of the mat object
int im_width = images[0].cols;
int im_height = images[0].rows;
for(int j=0; j < images.size(); j++) {
resize(images[j],images[j],Size(im_width, im_height),1.0,1.0,INTER_CUBIC);
}
//int numComponents = 2;
//double threshold = 10.0;
//creats a faceRecognizer to train with given images
Ptr<cv::face::FisherFaceRecognizer> model = cv::face::FisherFaceRecognizer::create();
model->train(images, labels);
string camera_msg = "No camera found";
Mat webcam; // creates Mat object for to store frames
VideoCapture cap(0); // opens default webcam
if(!cap.isOpened()) {
return env->NewStringUTF(camera_msg.c_str());
}
face_cascade.load(face_cascade_name); //loads xml file into classifier
//load capture device into Mat object
while (cap.read(webcam)) {
vector<Rect> faces;
Mat frame_gray; //will be used to store grayscale copy of webcam
cvtColor(webcam, frame_gray, COLOR_BGR2GRAY); //coverts Mat object frames into grayscale
equalizeHist(frame_gray, frame_gray); //maps input distrubution to more uniform distribution
//locate the faces in the frame
face_cascade.detectMultiScale(frame_gray, faces, 1.1, 5, 0|CASCADE_SCALE_IMAGE,Size(30,30));
for(size_t i=0; i < faces.size(); i++) {
Rect face_i = faces[i]; //process faces by frame
Mat face = frame_gray(face_i); //takes the face from the live images
//resize faces for prediction
Mat face_resized;
resize(face,face_resized,Size(im_width, im_height),1.0,1.0,INTER_CUBIC);
int prediction = model->predict(face_resized); //predict based on resize faces
if(prediction == 1 ) {
printId = "Matthew";
}
else if (prediction == 2) {
printId = "Greg";
return env->NewStringUTF(printId.c_str());
}
else if(prediction != 1 || 2 ){
printId = "Unknown";
}
rectangle(webcam, face_i, CV_RGB(0,255,0), 1); //draws a rectangle around the face
string box_text = "Prediction = " + printId;
int pos_x = std::max(face_i.tl().x - 10, 0);
int pos_y = std::max(face_i.tl().y - 10, 0);
putText(webcam, box_text, Point(pos_x,pos_y), FONT_HERSHEY_PLAIN, 1.0, CV_RGB(0,255,0), 1);
}
imshow("Webcam", webcam);
waitKey(1);
destroyAllWindows();
}
return env->NewStringUTF(printId.c_str());
}
Here's my Java code:
public class recognitionJNI{
static {
System.loadLibrary("recogjni");
}
private native String userName(String msg);
public static void main(String args[]) {
String result = new recognitionJNI().userName("Pass arg from c++ function");
System.out.println(result);
}
}
Try regenerating the header file, it looks like you changed your class name in the meantime and the name is no longer up to date. The name I get from that java class is:
Java_recognitionJNI_userName
But you have
Java_testJNIString_userName

Get a string from a c++ library with a java wrapper around it

Good Evening,
I have a c++ library file where I am trying to get a string value from but not by return.
This is for an Android Application build in Xamarin.
.cpp file
JNIEXPORT jint JNICALL Java_MyNamespace_ClassName_FunctionName
(JNIEnv *env, jclass obj, jstring returnString)
{
returnString = env->NewStringUTF("returnStringValue");
return 1;
}
In my Solution I have:
.cs File
namespace myNamespace
{
[DllImport("FolderName", EntryPoint = "Java_MyNamespace_ClassName_FunctionName")]
private static extern int FunctionName(IntPtr env, IntPtr thiz, IntPtr returnString);
void test_function()
{
IntPtr j = new IntPtr();
int status = FunctionName(JNIEnv.Handle, IntPtr.Zero, j);
string ss = j.ToString();
//Where I am expecting ss to be containing "returnStringValue".
}
}
Thanks #SushiHangover
We created a byte array
byte[] x = new byte[120];
Allocated that memory and copied it
System.Runtime.InteropServices.Marshal.AllocHGlobal()
System.Runtime.InteropServices.Marshal.Copy()
And then converted using:
System.Text.Encoding.UTF8.GetString()
Apparently this worked verry well.
Regards

While working with ffmpeg: Created function in C file and after compilation with NDK accessing from android activity, getting signal 11 error

After successfully fire command ndk-build I got .so file in my libs folder, then after some changes in gradle file I got native_libs.xml .idea/libraries folder.
Now I am accessing c function from my java code/ android activity. I am getting signal 11 error
My code is
C file
#include <jni.h>
#include <android/log.h>
#include <stdlib.h>
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#define LOG_TAG "mylib"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
//JNIEXPORT jint JNICALL Java_com_xxx_xxx_activities_SplashActivity_logFileInfo(JNIEnv * env, jobject this, jstring filename);
jint Java_com_xxx_xxx_activities_TutorialsActivity_logFileInfo(JNIEnv * env, jobject this, jstring filename)
{
av_register_all();
AVFormatContext *pFormatCtx;
const jbyte *str;
str = (*env)->GetStringUTFChars(env, filename, NULL);
if(avformat_open_input(&pFormatCtx, str, NULL, NULL)!=0)
{
LOGE("Can't open file '%s'\n", str);
return 1;
}
else
{
LOGI("File was opened\n");
LOGI("File '%s', Codec %s",
pFormatCtx->filename,
pFormatCtx->iformat->name
);
}
return 0;
}
Loading and try to access method in java code is
private static native int logFileInfo(String filename);
static {
System.loadLibrary("framegrabber");
}
In OnCreate of activity
logFileInfo(file.getAbsolutePath());
Finally error at point logFileInfo(file.getAbsolutePath()); is
A/libc: Fatal signal 11 (SIGSEGV), code 1, fault addr 0x106e in tid 8905 (Thread-20972)
Please replay if you have any solution, Thanking in advance.

Java writing byte array over JNI using O_direct

I am trying to use O_direct in Java over JNI in Linux.
here is the java part:
public class jnitest {
static {
System.loadLibrary("jnitest"); // Load native library at runtime
// hello.dll (Windows) or libhello.so (Unixes)
}
private native void test();
private native void write(String path, byte[] chunkpayload);
public static void main(String[] args) {
try{
jnitest t=new jnitest();
byte[] chunk=new byte[5];
chunk[0]=1;
chunk[1]=2;
chunk[2]=3;
chunk[3]=4;
chunk[4]=5;
String s="outtest";
t.write(s,chunk);
}catch(Exception e){
System.out.println("fehler lol");
}
}
}
This is the C part:
#define _GNU_SOURCE
#include <jni.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include "jnitest.h"
#define BLOCKSIZE 512
JNIEXPORT void JNICALL Java_jnitest_write(JNIEnv *env, jobject obj, jstring jpath, jbyteArray jchunkpayload){
const char *path=(*env)->GetStringUTFChars(env, jpath, 0);
printf("path=%s \n",path);
(*env)->ReleaseStringUTFChars(env, jpath, path);
int len = (*env)->GetArrayLength (env,jchunkpayload);
printf("lenght= %d \n",len);
unsigned char* payload =(*env)->GetByteArrayElements(env,jchunkpayload,0);
int i=0;
for(i=0;i<len-1;i++){
printf("%02x \n",(int)payload[i]);
}
void *buffer;
int fd = open(path, O_SYNC|O_APPEND|O_CREAT|O_DIRECT);
posix_memalign(&buffer,BLOCKSIZE,BLOCKSIZE);
memcpy(buffer,payload,len);
write(fd,buffer,BLOCKSIZE);
printf("writen to file\n");
(*env)->ReleaseByteArrayElements(env,jchunkpayload,payload,JNI_ABORT);
free(buffer);
return;
}
JNIEXPORT void JNICALL Java_jnitest_test(JNIEnv *env, jobject obj){
printf("test\n");
return;
}
The program does not fail but the data is never written. I know I can use JNA, but i want to use JNI. Does somebody have a working example for writing a byte array in java over JNI using O_direct?

How to get sent string from java code to native C in Android

I am working on android app in which I am using NDK for a small stuff. How to get sent string from java code to native C. I want to get a value in native C code which was sent from java code.
Here is my code which I wrote in activity
observer("test#gmail.com");
public native void observer(String email);
And Native code is this
void
Java_pl_pelotasplus_actionafteruninstall_MainActivity_observer(JNIEnv* env, jobject thiz) {
// I want to get email.. How to get
}
Thanks in advance.
Always use javah to generate the headers so you don't have any mistakes. Also recommend sticking it in a batch file so you can update with ease.
From source folder:
...\src> javah pl.pelotasplus.actionafteruninstall.MainActivity
Will generate the following .h file:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for pl_pelotasplus_actionafteruninstall_MainActivity */
#ifndef _Included_pl_pelotasplus_actionafteruninstall_MainActivity
#define _Included_pl_pelotasplus_actionafteruninstall_MainActivity
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: pl_pelotasplus_actionafteruninstall_MainActivity
* Method: observer
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_pl_pelotasplus_actionafteruninstall_MainActivity_observer
(JNIEnv *, jobject, jstring);
#ifdef __cplusplus
}
#endif
#endif
Note the header does not include names for the parameters, so add them when implementing like this:
JNIEXPORT void JNICALL Java_pl_pelotasplus_actionafteruninstall_MainActivity_observer
(JNIEnv *env, jobject thiz, jstring email){
const char *nativeEmailString = (*env)->GetStringUTFChars(env, email, 0);
// use your string
(*env)->ReleaseStringUTFChars(env, email, nativeEmailString);
}
try this:
void Java_pl_pelotasplus_actionafteruninstall_MainActivity_observer(JNIEnv* env, jobject thiz, jstring jstr) {
char* email = jstringToCharArray(env, jstr);
}
jstringToCharArray:
char* jstringToCharArray(JNIEnv* env, jstring jstr)
{
char* rtn = NULL;
jclass clsstring = env->FindClass("java/lang/String");
jstring strencode = env->NewStringUTF("utf-8");
jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");
jbyteArray barr= (jbyteArray)env->CallObjectMethod(jstr, mid, strencode);
jsize alen = env->GetArrayLength(barr);
jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);
if (alen > 0)
{
rtn = (char*)malloc(alen + 1);
memcpy(rtn, ba, alen);
rtn[alen] = 0;
}

Categories

Resources