java - usar - La forma más eficiente de enviar imágenes en YUV_420_888 desde Android a JNI en OpenCV Mat
usar opencv en android studio (2)
Tengo una aplicación para Android en la que quiero ejecutar un proceso de procesamiento de imágenes OpenCV
imágenes en vivo desde la API de Camera2
Android. Actualmente, si no hago ningún procesamiento, puedo recibir imágenes en la función OnImageAvailble
a 30 fps para un marco regular de 1280x720
.
Ahora, como un truco sucio, solicito Imágenes de ImageReader en formato JPEG y luego paso el Bitmap a jni
que reduce el rendimiento mucho.
¿Cuál es la forma más eficiente de pasar el marco YUV a jni
en el objeto cv Mat
? Además, quiero convertir este marco a RGB
para su posterior procesamiento. ¿Debo cambiar el formato en el lado de Java o debo pasar el objeto Mat
a jni
y convertir el espacio de color allí solo?
Tal vez sea útil para usted: ya que hacemos mucho procesamiento de imágenes, escribimos una biblioteca para ese propósito en nuestra empresa. No está escrito en C pero es bastante performante. Después de la conversión, simplemente puede pasar el puntero Mat a su código C a través de JNI.
Convierte YUVs (formato de cámara estándar de Android YUV_420_888) en alfombrillas RGB. Además, también permite un recorte eficiente del YUV antes de la conversión (importante para imágenes muy grandes, de lo contrario, sería necesario convertir toda la imagen y luego recortar, lo que es costoso). El uso es muy simple:
Mat mat = Yuv.toMat(image)
Todo lo que haga en C ++ es mucho más rápido que el equivalente de Java por razones obvias, incluidas las transformaciones de YUV a RGB (incluso si la implementación de Java se basa en bibliotecas compiladas).
Puede pasar directamente un puntero desde su Mat existente en java directamente a C ++ a través de JNI. Suponiendo que quiero hacer Canny () usando C ++ y JNI, y tengo una función JNI definida de esta manera:
// In Java
public static native boolean nativeCanny(long iAddr);
Observe el parámetro iAddr largo , que es un puntero directo a mi Mat en Java. Lo invocas así:
// In Java
nativeCanny(myImage.getNativeObjAddr());
La implementación de esta función en C ++ recibiría este puntero de forma similar a esta (reemplace con jlong si esto no funciona):
// 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;
}
Y todo lo que le hice al img Mat, también sucede en el java myImage Mat, después de todo es un indicador, por lo que nunca hicimos una copia.
Que yo sepa, eso es lo más rápido que puede ser.