Procesamiento de datos de la vista previa de la cámara con Android L y Camera2 API

Estoy trabajando en una aplicación para Android que está procesando la imagen de entrada de la cámara y la muestra al usuario. Esto es bastante simple, registro un PreviewCallback en el objeto de la cámara con el setPreviewCallbackWithBuffer . Esto es fácil y funciona sin problemas con la antigua cámara API

 public void onPreviewFrame(byte[] data, Camera cam) { // custom image data processing } 

Estoy intentando portar mi app para aprovechar la nueva API de Camera2 y no estoy seguro de cómo exactamente haré eso. He seguido el Camera2Video en L Preview muestras que permite grabar un video. Sin embargo, no hay transferencia de datos de imagen directa en la muestra, por lo que no entiendo dónde exactamente voy a obtener los datos de píxeles de la imagen y cómo procesarla.

¿Podría alguien ayudarme o sugerir la manera cómo se puede obtener la funcionalidad de PreviewCallback en android L, o cómo es posible procesar los datos de vista previa de la cámara antes de mostrarlo a la pantalla? (No hay devolución de llamada de vista previa en el objeto de cámara)

¡Gracias!

Dado que la API de Camera2 es muy diferente de la API de Camera actual, podría ayudar a revisar la documentación.

Un buen punto de partida es el ejemplo de camera2basic . Demuestra cómo usar Camera2 API y configurar ImageReader para obtener imágenes JPEG y registrar ImageReader.OnImageAvailableListener para recibir esas imágenes

Para recibir los fotogramas de vista previa, debe agregar la superficie de su ImageReader a setRepeatingRequest 's CaptureRequest.Builder .

Además, debe establecer el formato de ImageReader a YUV_420_888 , que le dará 30fps a 8MP (La documentación garantiza 30fps a 8MP para Nexus 5).

Necesitaba lo mismo, así que utilicé su ejemplo y agregé una llamada a una nueva función cuando la cámara está en estado de vista previa.

 private CameraCaptureSession.CaptureCallback mCaptureCallback = new CameraCaptureSession.CaptureCallback() private void process(CaptureResult result) { switch (mState) { case STATE_PREVIEW: { if (buttonPressed){ savePreviewShot(); } break; } 

savePreviewShot() es simplemente una versión reciclada del original captureStillPicture() adaptado para usar la plantilla de vista previa.

  private void savePreviewShot(){ try { final Activity activity = getActivity(); if (null == activity || null == mCameraDevice) { return; } // This is the CaptureRequest.Builder that we use to take a picture. final CaptureRequest.Builder captureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); captureBuilder.addTarget(mImageReader.getSurface()); // Orientation int rotation = activity.getWindowManager().getDefaultDisplay().getRotation(); captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation)); CameraCaptureSession.CaptureCallback CaptureCallback = new CameraCaptureSession.CaptureCallback() { @Override public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss:SSS"); Date resultdate = new Date(System.currentTimeMillis()); String mFileName = sdf.format(resultdate); mFile = new File(getActivity().getExternalFilesDir(null), "pic "+mFileName+" preview.jpg"); Log.i("Saved file", ""+mFile.toString()); unlockFocus(); } }; mCaptureSession.stopRepeating(); mCaptureSession.capture(captureBuilder.build(), CaptureCallback, null); } catch (Exception e) { e.printStackTrace(); } }; 

En la clase ImageReader.OnImageAvailableListener, cierre la imagen después de leer como se muestra a continuación (esto liberará el búfer para la próxima captura). Tendrá que manejar la excepción al cerrar

  Image image = imageReader.acquireNextImage(); ByteBuffer buffer = image.getPlanes()[0].getBuffer(); byte[] bytes = new byte[buffer.remaining()]; buffer.get(bytes); image.close(); 

Combinando unas cuantas respuestas en una más digerible porque la respuesta de @ VP, aunque técnicamente clara, es difícil de entender si es la primera vez que se mueve de cámara a cámara2:

Utilizando https://github.com/googlesamples/android-Camera2Basic como punto de partida, modifique lo siguiente:

En createCameraPreviewSession() init una nueva Surface de mImageReader

 Surface mImageSurface = mImageReader.getSurface(); 

Agregue esa nueva superficie como destino de salida de su variable CaptureRequest.Builder . Utilizando el ejemplo de Camera2Basic, la variable será mPreviewRequestBuilder

 mPreviewRequestBuilder.addTarget(mImageSurface); 

Aquí está el fragmento con las nuevas líneas (vea mis comentarios @AngeloS):

 private void createCameraPreviewSession() { try { SurfaceTexture texture = mTextureView.getSurfaceTexture(); assert texture != null; // We configure the size of default buffer to be the size of camera preview we want. texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight()); // This is the output Surface we need to start preview. Surface surface = new Surface(texture); //@AngeloS - Our new output surface for preview frame data Surface mImageSurface = mImageReader.getSurface(); // We set up a CaptureRequest.Builder with the output Surface. mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); //@AngeloS - Add the new target to our CaptureRequest.Builder mPreviewRequestBuilder.addTarget(mImageSurface); mPreviewRequestBuilder.addTarget(surface); ... 

A continuación, en setUpCameraOutputs() , cambie el formato de ImageFormat.JPEG a ImageFormat.YUV_420_888 cuando ImageFormat.YUV_420_888 su ImageReader . (PS, también recomiendo bajar su tamaño de vista previa para una operación más suave – una buena característica de Camera2)

 mImageReader = ImageReader.newInstance(largest.getWidth() / 16, largest.getHeight() / 16, ImageFormat.YUV_420_888, 2); 

Por último, en su método onImageAvailable() de ImageReader.OnImageAvailableListener , asegúrese de usar la sugerencia de @ Kamala porque la vista previa se detendrá después de unos pocos fotogramas si no lo cierra

  @Override public void onImageAvailable(ImageReader reader) { Log.d(TAG, "I'm an image frame!"); Image image = reader.acquireNextImage(); ... if (image != null) image.close(); } 
  • Android: procesamiento de imágenes en tiempo real
  • Incluir OpenCV en el paquete de aplicaciones de Android
  • Detectar los límites de un documento en una imagen usando opencv java
  • OpenCV obtiene píxeles negros dentro del límite del contorno
  • Crear múltiples secciones en un marco y hacer que cada sección funcione singleton
  • Error con setPixels
  • Comparar dos imágenes en android
  • Calcular la relación de aspecto de la imagen de destino Transformar perspectiva
  • Cómo desenfocar una parte de la imagen en Android?
  • Ajuste de saturación y ColorFilter a la imagen simultáneamente
  • ¿Hay alguna biblioteca java para leer los códigos de barras del número vin de la imagen?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.