2012-05-27 21 views
17

Quiero hacer el procesamiento de imágenes con una imagen sin mostrar en la pantalla, lo que obviamente reduce el rendimiento.Android SDK: Obtener la imagen de la cámara sin previsualizar sin mostrarlo

Según las respuestas a este hilo Taking picture from camera without preview no fue posible en Android 1.5, pero ¿alguien sabe si es posible en Android 4 (API nivel 15)?

+0

Acabo de probar la solución dummy SurfaceTexture (método 2) en un Samsung Galaxy s5. Falla después de algunos cuadros. Mi solución es llamar a updateTexImage, pero use un nombre de textura no válido con un contexto GL válido. Después de silenciar la excepción resultante, todo funciona sin problemas. – user3693576

Respuesta

41

En Android 4, la opción más simple para recibir datos de imágenes en bruto sin mostrarlo en la pantalla es utilizar la llamada Camera.setPreviewTexture() para enrutar los marcos de vista previa a la GPU.

Se puede utilizar de dos maneras:

  1. Haga su procesamiento real en la GPU: Establecer un contexto OpenGL (OpenGL ES 2 tutorial), y crear un objeto SurfaceTexture en ese contexto. A continuación, pase ese objeto a setPreviewTexture y comience la vista previa. Luego, en su código OpenGL, puede llamar a SurfaceTexture.updateTexImage, y el ID de textura asociado con SurfaceTexture se actualizará al último marco de vista previa de la cámara. También puede volver a leer los datos de textura RGB en la CPU para su posterior procesamiento utilizando glReadPixels, si lo desea.
  2. Haga su procesamiento en la CPU: simplemente puede crear un objeto SurfaceTexture ficticio sin ningún contexto de OpenGL configurado. Pase cualquier número entero que desee como ID de textura, y conecte SurfaceTexture a la cámara usando setPreviewTexture. Siempre que no llame a updateTexImage, SurfaceTexture simplemente descartará todos los datos que la cámara le pase. Luego configure las devoluciones de vista previa usando setPreviewCallback, y use esa información (generalmente en formato YUV) para el procesamiento de la CPU. Esto es probablemente menos eficiente que el # 1, pero no requiere saber OpenGL.
+0

¿Alguien ha encontrado un ejemplo simple de usar glReadPixels después de que SurfaceTexture.updateTexImage regrese? – wobbals

+0

El método 2 no funciona para Nexus 4. – user1914692

+0

@wobbals: No se puede 'glReadPixels()' directamente la salida de la cámara (mismo problema que http: // stackoverflow.com/questions/19366660/how-to-save-surfacetexture-as-bitmap/19370209 # 19370209). Primero tráigalo a un pbuffer. Algunos consejos para ejemplos aquí: http://stackoverflow.com/questions/20710204/android-camera-preview-on-surfacetexture/21104769#21104769 – fadden

1

Como no tengo permitido comentar. En cuanto a la respuesta de Eddy. Debe trabajar con esto en el NDK ya que el uso de la interfaz Java anulará cualquier beneficio de rendimiento. Tener que trabajar con un PixelBuffer es una locura desde el punto de vista del rendimiento. Su conversión de RGBA888 a YUV también debe hacerse en C.

No intente usar un TextureView, ya que será aún peor. Tendría que copiar los Pixels en un mapa de bits y luego desde un mapa de bits en una matriz antes de la conversión a YUV. Esto, por sí mismo, toma casi el 30% de la utilización de la CPU en un nuevo y flamante Nexus 7 2013.

La forma más eficiente es hablar directamente con Camera.h y omitir todas las API de Android. Puede crear su propio búfer e interceptar los datos del YUV antes de que vaya a otro lado.

+1

Si bien las devoluciones de vista previa no son tan eficientes como me gustaría, no son horrible. Obtiene un byte [] de datos YUV por cuadro, que puede enviarse a través de JNI al código de procesamiento nativo con cero copias. No se requiere conversión a Bitmap ni a nada más. Usar Camera.h directamente es una mala idea, porque esa interfaz es privada y está sujeta a cambios en cualquier momento. –

+0

Las devoluciones de vista previa solo funcionan con una superficie. La pregunta era cómo hacerlo sin mostrarlo en absoluto. La única forma de hacerlo sin Surface es usar PixelBuffer. La devolución de llamada estándar con Surface es mejor desde el punto de vista del rendimiento. Cada devolución de llamada tiene dos ciclos. La cámara copia en el búfer interno; luego en el buffer de superficie RGBA. El segundo ciclo copia el búfer interno en el búfer de devolución de llamada. – bond

+0

Realmente no estoy seguro de lo que quiere decir con PixelBuffer: no hay API con ese nombre que conozco en Android (¿se refiere a Bitmap?). Las devoluciones de vista previa funcionan bien con setPreviewTexture() además de setPreviewDisplay(), y la primera no requiere vista previa de dibujo a ningún elemento de UI. Las copias en las capas nativa y JNI son un arrastre de rendimiento, estoy de acuerdo, y es por eso que también sugerí el enfoque de procesamiento de GPU, que no tiene ningún costo. –

1

Mostrar vista previa en la pantalla no tiene consecuencias en el rendimiento. En todos los dispositivos que conocí, la salida de la cámara está "conectada" a una superficie o textura sin CPU, toda la conversión de color y escalado está a cargo de hardware dedicado.

Puede haber otras razones para "ocultar" la vista previa, pero tenga en cuenta que el objetivo de la API era en primer lugar asegurarse de que el usuario vea lo que llega de la cámara a la aplicación, por razones de privacidad y seguridad .

Cuestiones relacionadas