Самый эффективный способ отправки изображения в YUV_420_888 с Android на JNI в макете OpenCV

У меня есть приложение для Android, в котором я хочу запустить обработку изображений OpenCV на прямых изображениях с android Camera2 API. В настоящее время, если я не занимаюсь обработкой, я могу получать изображения в функции OnImageAvailble со скоростью 30 кадров в секунду для обычного кадра 1280x720.

Теперь, будучи грязным взломом, я запрашиваю изображения из ImageReader в формате JPEG, а затем передаю Bitmap в jni что сильно снижает производительность.

Какой самый эффективный способ передать кадр YUV в jni в объекте cv Mat. Кроме того, я хочу преобразовать этот кадр в RGB для дальнейшей обработки. Должен ли я изменить формат на стороне Java или передать объект Mat в jni и преобразовать только цветовое пространство.

Ответ 1

Все, что вы делаете в C++, намного быстрее, чем эквивалент Java по очевидным причинам, включая преобразования YUV в RGB (даже если реализация Java зависит от скомпилированных библиотек).

Вы можете напрямую передать указатель из существующего Mat в java прямо на C++ через JNI. Предположим, что я хочу делать Canny() с помощью C++ и JNI, и у меня есть функция JNI, определенная следующим образом:

// In Java
public static native boolean nativeCanny(long iAddr);

Обратите внимание на длинный параметр iAddr, который является прямым указателем на мой Mat в Java. Вы вызываете это так:

// In Java
nativeCanny(myImage.getNativeObjAddr());

Реализация этой функции в C++ получит этот указатель аналогичным образом (замените long jlong, если это не сработает):

// In C++
JNIEXPORT jboolean JNICALL
VeryLongName_nativeCanny(JNIEnv *env, jobject instance, long iAddr) {
    cv::Mat* img = (cv::Mat*) iAddr;
    cv::Canny(*img, *img, 80, 100, 3);
    return true;
}

И что бы я ни делал с img Mat, это также происходит в java myImage Mat, ведь он был указателем, поэтому мы никогда не делали копию.

Насколько я знаю, это так быстро, как это происходит.

Ответ 2

Может быть, полезно для вас: поскольку мы много обрабатываем изображения, мы написали для этой цели библиотеку для этой цели. Это не написано на C, но оно довольно показательно. После преобразования вы можете просто передать указатель Mat вниз на ваш код C через JNI.

Он преобразует YUV (стандартный формат камеры Android YUV_420_888) в RGB Mats. Кроме того, он также позволяет эффективно обрезать YUV перед конверсией (важно для очень больших изображений, иначе вам нужно будет преобразовать изображение целиком, а клип впоследствии - дорого). Использование очень просто:

Mat mat = Yuv.toMat(image)

https://github.com/quickbirdstudios/yuvToMat