Собственный файл Android, прочитанный из папки активов с помощью tflite BuildFromFile()

У меня есть собственный код Android (общий объект C++), который хочет, чтобы файл read модели сохранялся в папке assets при создании APK.

Tensorflow Lite имеет два API: FromFile и FromBuffer.

static std::unique_ptr<FlatBufferModel> BuildFromFile(const char* filename, ErrorReporter* error_reporter);

static std::unique_ptr<FlatBufferModel> BuildFromBuffer(const char* buffer, size_t buffer_size, ErrorReporter* error_reporter);

со следующим кодом я могу получить доступ к FromBuffer:

Java код:

private AssetManager mgr;

// Get mgr 
mgr = getResources().getAssets();

C++ код:

AAssetDir* assetDir = AAssetManager_openDir(mgr, "");
const char* filename = (const char*)NULL;
while ((filename = AAssetDir_getNextFileName(assetDir)) != NULL) {
    AAsset* asset = AAssetManager_open(mgr, filename, AASSET_MODE_STREAMING);
    char buf[BUFSIZ];
    int nb_read = 0;
    FILE* out = fopen(filename, "w");
    while ((nb_read = AAsset_read(asset, buf, BUFSIZ)) > 0)
        fwrite(buf, nb_read, 1, out);
    fclose(out);
    AAsset_close(asset);
}
AAssetDir_close(assetDir);

Есть идеи, как получить доступ к папке assets для использования BuildFromFile?

1
0
609
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я не думаю, что вы можете использовать BuildFromFile без копирования файла ресурса в локальный файл (что эквивалентно тому, что вы сделали выше, и тогда BuildFromBuffer более удобен в этом случае).

Если вы хотите избежать копирования памяти, вот что вы можете сделать:

  1. (Java) Загрузите модель с помощью сопоставления памяти.
    AssetFileDescriptor fileDescriptor = getResources().getAssets().openFd(filePath);\
    FileInputStream inputStream = new FileInputStream(fileDescriptor.getFileDescriptor());\
    FileChannel fileChannel = inputStream.getChannel();\
    long startOffset = fileDescriptor.getStartOffset();\
    long declaredLength = fileDescriptor.getDeclaredLength();\
    MappedByteBuffer modelBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, startOffset, declaredLength);
  1. (Java) Передайте сопоставленный файл на C++ через jni, например, определив следующий метод:
    private static native void initJniWithByteBuffer(ByteBuffer modelBuffer)
  1. (С++) Используйте файл буфера для инициализации вашей модели:
    Java_xxxxxx_initJniWithByteBuffer(JNIEnv* env, jclass thiz, jobject model_buffer) {\
      char* buffer = static_cast<char*>(env->GetDirectBufferAddress(model_buffer));\
      size_t buffer_size = static_cast<size_t>(env->GetDirectBufferCapacity(model_buffer));\
    }

У меня сработало, с одной оговоркой: если вы храните указатель сопоставления на стороне C++ и повторно используете его позже, не забудьте сохранить объект MappedByteBuffer Java до тех пор, пока вам нужен указатель.

Seva Alekseyev 10.10.2022 20:36

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