android c++ bitmap jni image-manipulation

decodificación y manipulación de imágenes usando JNI en android



c++ bitmap (2)

fondo

En algunas aplicaciones, es importante manejar imágenes grandes sin OOM y también rápidamente.

Para esto, JNI (o renderscript, que lamentablemente carece de documentación) puede ser una buena solución.

En el pasado, tuve éxito usando JNI para rotar mapas de bits enormes mientras evitaba OOM (enlace aquí , aquí y aquí ). fue una experiencia agradable (aunque molestamente dura), pero al final funcionó.

el problema

Android Framework tiene muchas funciones para manejar bitmaps, pero no tengo idea de cuál es la situación en el lado JNI.

Ya sé cómo pasar un mapa de bits del "mundo java" de android al "mundo JNI" y viceversa.

Lo que no sé es qué funciones puedo usar en el lado JNI para ayudarme con bitmaps.

Deseo poder realizar todas las operaciones de imagen (incluida la decodificación) en JNI, de modo que no tenga que preocuparme por OOM cuando me presenten imágenes grandes, y al final del proceso, podría convertir los datos a Java- mapa de bits (para mostrar al usuario) y / o escribirlo en un archivo.

una vez más, no quiero convertir los datos en el lado JNI a un mapa de bits java solo para poder ejecutar esas operaciones.

Resulta que hay algunas bibliotecas que ofrecen muchas funciones (como JavaCV ), pero son bastante grandes y no estoy muy seguro de sus características y si realmente hacen la decodificación en el lado JNI, entonces preferiría para poder saber qué es posible a través de la función incorporada de JNI de Android.

la pregunta

¿Qué funciones están disponibles para la manipulación de imágenes en el lado JNI en Android?

por ejemplo, ¿cómo podría ejecutar la detección de rostros en mapas de bits, aplicar matrices, mapas de bits de baja resolución, mapas de bits de escala, etc.?

para algunas de las operaciones, ya puedo pensar en una forma de implementarlas (escalar imágenes es bastante fácil, y la wikipedia puede ayudar mucho), pero algunas son muy complejas.

incluso si implemento las operaciones yo solo, quizás otros lo hayan hecho de manera mucho más eficiente, pensando en las tantas optimizaciones que C / C ++ puede tener.

¿estoy realmente solo cuando voy al lado JNI de Android, donde tengo que implementar todo desde cero?

Para dejarlo en claro, lo que me interesa es:

entrada de mapa de bits en java -> manipulación de imágenes puramente en JNI y C / C ++ (sin conversión a objetos java en absoluto) -> salida de mapa de bits en java.


"función JNI incorporada de Android" es una especie de contradicción. Es técnicamente correcto que muchas clases de Android Framework Java utilicen JNI en algún lugar de la cadena para invocar bibliotecas nativas.

Pero hay tres reservas con respecto a esta declaración.

  1. Estos son "detalles de implementación", y están sujetos a cambios sin previo aviso en cualquier próxima versión de Android, o cualquier fork (ej. Kindle), o incluso la versión OEM que no se considera una "bifurcación" (por ejemplo, construida por Samsung o Quallcom SOC).

  2. La forma en que se implementan los métodos nativos en las clases centrales de Java es diferente de la JNI "clásica". Estos métodos están precargados y almacenados en caché por la JVM y, por lo tanto, no sufren la mayoría de los gastos generales típicos de las llamadas JNI.

  3. No hay nada que su código Java o nativo pueda hacer para interactuar directamente con los métodos JNI de otras clases, especialmente las clases que constituyen el marco del sistema.

Dicho todo esto, puedes estudiar el código fuente de Android , encontrar las bibliotecas nativas que respaldan clases y métodos específicos (por ejemplo, detección de rostros) y usar estas bibliotecas en tu código nativo, o construir una capa JNI propia para usa estas bibliotecas desde tu código de Java.

Para dar un ejemplo específico, la detección de rostros en Android se implementa a través de la clase android.media.FaceDetector , que carga libFFTEm.so . Puede mirar el código nativo y usarlo como lo desee. No debe suponer que libFFTEm.so estará presente en el dispositivo, o que la biblioteca en el dispositivo tendrá la misma API.

Pero en este caso específico, no es un problema, porque todo el trabajo de neven está completamente basado en software. Por lo tanto, puede copiar este código en su totalidad, o solo partes relevantes de él, y hacerlo parte de su biblioteca nativa. Tenga en cuenta que para muchos dispositivos simplemente puede cargar y usar /system/lib/libFFTEm.so y nunca sentir incomodidad, hasta que encuentre un sistema que se portará mal.

Una conclusión digna de mención que puede hacer al leer el código nativo es que los algoritmos subyacentes ignoran la información del color. Por lo tanto, si la imagen para la que desea encontrar las coordenadas faciales proviene de la fuente YUV, puede evitar una gran sobrecarga si llama

// run detection btk_DCR_assignGrayByteImage(hdcr, bwbuffer, width, height); int numberOfFaces = 0; if (btk_FaceFinder_putDCR(hfd, hdcr) == btk_STATUS_OK) { numberOfFaces = btk_FaceFinder_faces(hfd); } else { ALOGE("ERROR: Return 0 faces because error exists in btk_FaceFinder_putDCR./n"); }

directamente con su matriz de bytes YUV (o Y), en lugar de convertirla a RGB y volver a YUV en android.media.FaceDetector.findFaces () . Si su buffer YUV proviene de Java, puede construir su propia clase YuvFaceDetector que será una copia de android.media.FaceDetector con la única diferencia de que YuvFaceDetector.findFaces() tomará valores Y (luminancia) solo en lugar de un mapa de bits, y evitar la conversión de RGB a Y

Algunas otras situaciones no son tan fáciles como esto. Por ejemplo, los códecs de video están estrechamente conectados a la plataforma de hardware, y no se puede simplemente copiar el código de libstagefright.so a su proyecto. El códec Jpeg es una bestia especial. En sistemas modernos (IIRC, desde 2.2), puede esperar que /system/lib/libjpeg.so esté presente. Pero muchas plataformas también tienen implementaciones HW mucho más eficientes de códecs Jpeg a través de libstagefright.so o OpenMAX, y a menudo estos se usan en los métodos android.graphics.Bitmap.compress () y android.graphics.BitmapFactory.decode *** () .

Y también hay un libjpeg-turbo optimizado, que tiene sus propias ventajas sobre /system/lib/libjpeg.so .