Android JNI - загрузка файла предиктора формы dlib

В обычном проекте Visual Studio C++ я использую следующий код для загрузки файла предиктора формы в переменную dlib shape_predictor:

    dlib::shape_predictor spredictor;
    //calling the file with a relative path
    dlib::deserialize("sp68fl.dat") >> spredictor;

Однако, используя JNI в Android, я загружаю этот файл из своей деятельности и передаю его как байтовый массив. Итак, у меня есть jbyteArray, который является файлом shape_predictor_68_face_landmarks.dat, который используется для обнаружения лиц с помощью Dlib.

Я нашел перегруженный метод deserialize (serializable_type & item, std:: istream & in), но не могу понять, как его использовать (возможно, мне нужно преобразовать jbyteArray в этот istream).

Как я могу загрузить этот файл в dlib::shape_predictor из jbyteArray?

РЕДАКТИРОВАТЬ:

Это то, что я пробовал до сих пор:

#include <jni.h>
#include <dlib\image_processing.h>
#include <dlib\image_processing\frontal_face_detector.h>
#include <dlib\image_processing\render_face_detections.h>
#include <dlib\image_processing\generic_image.h>
#include <dlib\image_processing\full_object_detection.h>
#include <dlib\opencv.h>
#include <dlib\geometry.h>
#include <dlib\image_transforms.h>
#include <dlib\serialize.h>
#include <dlib\gui_widgets.h>
#include <dlib\image_io.h>

extern "C" {
struct membuf : std::streambuf
{
    membuf(char* begin, char* end) {
        this->setg(begin, begin, end);
    }
};


JNIEXPORT jstring JNICALL
Java_br_edu_infnet_test16_MainActivity_stringFromJNI(JNIEnv *env, jobject daobj,
                                                     jbyteArray fileBytes,
                                                     jint fileSize) {
    dlib::shape_predictor spredictor;

    jboolean isCopy = true;
    jbyte * a = env->GetByteArrayElements(fileBytes, &isCopy);
    char* teste = (char *) a;

    std::ifstream in;
    //stream is not loading? stream size is zero after read method
    in.read(teste, fileSize);

    try {
        dlib::deserialize(spredictor, in);
    } catch (dlib::serialization_error &serializationError) {
        //deserialize method fails. Dlib error: deserializing object of type int
        std::cout << "ERROR: " << serializationError.what();
    }

    in.close();
    env->ReleaseByteArrayElements(fileBytes, a, JNI_ABORT);

    const char *cppString = "Diego";
    jstring javaString = env->NewStringUTF(cppString);
    return javaString;
}
}

Деятельность, отправляющая байтовый массив:

package br.edu.infnet.test16;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.TextView;

import java.io.InputStream;

public class MainActivity extends AppCompatActivity {

    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("native-lib");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Example of a call to a native method
        TextView tv = findViewById(R.id.sample_text);
//        tv.setText(stringFromJNI());
        byte[] buffer = null;
        try {
            InputStream inputStream = getAssets().open("sp68fl.dat");
            int size = inputStream.available();
            buffer = new byte[size];
            inputStream.read(buffer);
            inputStream.close();
            stringFromJNI(buffer, size);
        } catch (Exception e) {
            e.printStackTrace();
            Log.e("ERRO", "DEU EEEEEEERRO: " + e.getMessage());
        }
    }

    public native String stringFromJNI(byte[] fileBytes, int fileSize);
}

Похоже, проблема в том, что ifstream не загружается с помощью переменной teste, которая является указателем на символ. Этот файл имеет размер около 100 МБ.

1 ответ

Вы можете открыть файл в C++. Проблема в том, что в Android вам нужен полный путь к имени файла, а не текущий каталог, на который вы можете положиться. Может быть проще использовать Java API для подготовки полного пути и передачи строки в C++ вместо отправки буфера.

Если это невозможно, вы должны преобразовать jbyteArray в char [] (см. Как преобразовать jbyteArray в native char* в jni?), А затем создать std::istream, как в разделе Получить istream из char *.

У меня была та же проблема, я только дал разрешение на чтение и запись в хранилище и работал. Попробуйте добавить в манифест:

И попросите разрешения

requestPermissions(новая строка []{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE}, REQUEST_PERMISSION);

Я сохранил файлы в корневом каталоге и использовал абсолютный путь к файлу.

Другие вопросы по тегам