2016-11-03 2 views
0

Я пытаюсь изменить некоторые значения в jfloatArray, прежде чем возвращать его в java-код Android. Я обнаружил, что не могу использовать обычный способ newArray[i] = result[i];, чтобы сделать это, и вместо этого я должен сделать env->SetFloatArrayElement(newArray,i,result[i]);.JNI SetFloatArrayElement() не работает

Проблема заключается в том, что эта функция вызывает ошибку:

[armeabi-v7a] Compile++ arm : tensorflow_mnist <= tensorflow_jni.cc jni/./tensorflow_jni.cc: In function '_jfloatArray* Java_jp_narr_tensorflowmnist_DigitDetector_detectDigit(JNIEnv*, jobject, jintArray)': jni/./tensorflow_jni.cc:171:14: error: 'JNIEnv' has no member named 'SetFloatArrayElement' env->SetFloatArrayElement(newArray,i,result[i]); ^

Код:

JNIEXPORT jfloatArray JNICALL 
TENSORFLOW_METHOD(detectDigit)(JNIEnv* env, jobject thiz, jintArray raw_pixels) { 

    jboolean iCopied = JNI_FALSE; 
    jint* pixels = env->GetIntArrayElements(raw_pixels, &iCopied); 
    jfloatArray newArray = env->NewFloatArray(2); 
    jfloat *result = process(reinterpret_cast<int*>(pixels)); 


    for(int i=0; i<2; ++i) { 

     //VLOG(0) << " (" << i << "): " << newArray[i]; 
     //newArray[i] = result[i]; 
     //env->SetFloatArrayElement(newArray,i,result[i]); 
    } 


    env->ReleaseIntArrayElements(raw_pixels, pixels, JNI_ABORT); 
    env->ReleaseFloatArrayElements(newArray, result, JNI_ABORT); 

    free(result); 

    return newArray; 
} 

ответ

2

I'm trying to modify some values in a jfloatArray before returning it to the java Android code. I've found that I can't use the regular way newArray[i] = result[i]; to do it and instead I should do env->SetFloatArrayElement(newArray,i,result[i]); .

Что заставляет вас думать, что? Как сообщает компилятор, JNI не имеет функции SetFloatArrayElement(). Функция одноэлементной установки используется только для массивов Object, то есть SetObjectArrayElement().

Существует несколько альтернатив для работы с примитивными массивами.

  • Классический механизм использовать соответствующую Get*ArrayElements() функцию, чтобы получить обычный массив, изменить массив, а затем ReleaseArrayElements(). Также обратите внимание, что при таком подходе, если вы хотите зафиксировать изменения (как и вы), вы должны использовать режим 0 или JNI_COMMIT, а не JNI_ABORT.

  • Для быстрого использования, такого как ваш, который не вызывает другие функции JNI, вы можете рассмотреть GetPrimitiveArrayCritical() и ReleasePrimitiveArrayCritical(). Однако вы не должны этого делать, если вы делаете какие-либо операции ввода-вывода между get и release.

  • Для вашего конкретного случая, однако, я бы предложил SetFloatArrayRegion(). Существует соответствующий GetFloatArrayRegion(), но он вам не нужен, потому что вы не заботитесь о закреплении или о начальных значениях элементов массива (Java).

Используя третий вариант может выглядеть следующим образом:

JNIEXPORT jfloatArray JNICALL 
TENSORFLOW_METHOD(detectDigit)(JNIEnv* env, jobject thiz, jintArray raw_pixels) { 

    jfloatArray newArray = env->NewFloatArray(2); 
    jint* pixels = env->GetIntArrayElements(raw_pixels, NULL); 

    jfloat *result = process(reinterpret_cast<int*>(pixels)); 

    env->ReleaseIntArrayElements(raw_pixels, pixels, JNI_ABORT); 
    env->SetFloatArrayRegion(newArray, 0, 2, result); 

    free(result); 

    return newArray; 
} 

Если бы вы могли полагаться на функцию process() работает очень быстро и без возможности блокировки, то вы могли бы рассмотреть возможность использования GetPrimitiveArrayCritical() и ReleasePrimitiveArrayCritical() к доступ к массиву пикселей. Возможно, что это будет более эффективно из-за того, что вы не сделаете копию массива пикселей, но отнюдь не обязательно, что используемый вами подход сделает копию. (Обратите внимание, в частности, что второй аргумент GetIntArrayElements() представляет собой переменную , она сообщает, была ли сделана копия, но не направляет ее).

+0

Я действительно нашел SetFloatArrayElement() в ссылке JNI для Unity3D. https://docs.unity3d.com/ScriptReference/AndroidJNI.SetFloatArrayElement.html Спасибо, хотя. Теперь я использую SetFloatArrayRegion(). – BernardoGO

+0

@BernardoGO, очевидно, AndroidJNI не отображает 1: 1 на JNI. Я вижу, как это может стать сюрпризом. FWIW, каноническая ссылка для JNI будет [предоставлена ​​Oracle] (https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/jniTOC.html). –

+0

О, я вижу. благодаря – BernardoGO