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.
- Transmisión de matriz a rsForEach en Renderscript Compute
- El tamaño de la imagen devuelta por Aviary es menor que el original
- ¿Es posible cortar un mapa de bits a piezas pequeñas sin cargar toda la cosa en la memoria?
- Cómo usar el LightingColorFilter para hacer que la forma de la imagen oscurezca a la luz
- Dilatación y erosión en Android
¿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!
- Animar la imagen de la cara - usando deformación?
- Optimización de la mezcla por pixel en mapas de bits de Android
- Usando get () y put () para acceder a valores de píxeles en OpenCV para Java
- Utilizando el array de bytes de la cámara en bruto para la realidad aumentada
- Biblioteca de procesamiento de imágenes para Android?
- Filtro esférico en android
- Imagen de Android magick
- Android - openCV, obtener parte de la imagen - comportamiento extraño
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(); }
- Formato de fecha basado en la configuración regional de usuario en android
- Inflar una vista en un subproceso de fondo