Vista previa de la cámara

He creado una aplicación de cámara basada en tutorial. La clase de vista previa que uso es de api-Demos "CameraPreview". He añadido una modificación desde aquí (la vista previa siempre giraba 90 °). Así que esto es cómo establecer el tamaño de vista previa:

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { // Now that the size is known, set up the camera parameters and begin // the preview. Camera.Parameters parameters = mCamera.getParameters(); Display display = ((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); if (display.getRotation() == Surface.ROTATION_0) { parameters.setPreviewSize(mPreviewSize.height, mPreviewSize.width); mCamera.setDisplayOrientation(90); } if (display.getRotation() == Surface.ROTATION_90) { parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height); } if (display.getRotation() == Surface.ROTATION_180) { parameters.setPreviewSize(mPreviewSize.height, mPreviewSize.width); } if (display.getRotation() == Surface.ROTATION_270) { parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height); mCamera.setDisplayOrientation(180); } parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height); requestLayout(); mCamera.setParameters(parameters); mCamera.startPreview(); } 

Sin embargo, la vista preliminar se muestra con una relación de aspecto incorrecta. ¿Es debido al código anterior o probablemente debido al diseño que uso ?:

 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <Button android:id="@+id/button_capture" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:text="@string/capture" /> <FrameLayout android:id="@+id/camera_preview" android:layout_width="100dp" android:layout_height="match_parent"/> 

Entonces, ¿cómo obtener la relación de aspecto correcta? Gracias por adelantado.

PS He leído la respuesta de: Vista previa de cámara Android extraño Pero esto no está funcionando para mí.

Intente cambiar los tamaños de vista previa con la adición de esta función:

 private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) { final double ASPECT_TOLERANCE = 0.05; double targetRatio = (double) w/h; if (sizes==null) return null; Camera.Size optimalSize = null; double minDiff = Double.MAX_VALUE; int targetHeight = h; // Find size for (Camera.Size size : sizes) { double ratio = (double) size.width / size.height; if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue; if (Math.abs(size.height - targetHeight) < minDiff) { optimalSize = size; minDiff = Math.abs(size.height - targetHeight); } } if (optimalSize == null) { minDiff = Double.MAX_VALUE; for (Camera.Size size : sizes) { if (Math.abs(size.height - targetHeight) < minDiff) { optimalSize = size; minDiff = Math.abs(size.height - targetHeight); } } } return optimalSize; } 

Y el ajuste de los tamaños de estos valores optimizados:

 List<Camera.Size> sizes = parameters.getSupportedPreviewSizes(); Camera.Size optimalSize = getOptimalPreviewSize(sizes, getResources().getDisplayMetrics().widthPixels, getResources().getDisplayMetrics().heightPixels); parameters.setPreviewSize(optimalSize.width, optimalSize.height); 

Espero que esto funcione 🙂

Atentamente

Henric

El siguiente código modifica la anchura / altura del contenedor de previsualización de la cámara para que coincida con la relación de aspecto de la vista previa de la cámara.

  Camera.Size size = camera.getParameters().getPreviewSize(); //landscape float ratio = (float)size.width/size.height; //portrait //float ratio = (float)size.height/size.width; preview = (FrameLayout) findViewById(R.id.camera_preview); int new_width=0, new_height=0; if(preview.getWidth()/preview.getHeight()<ratio){ new_width = Math.round(preview.getHeight()*ratio); new_height = cameraPreview.getHeight(); }else{ new_width = preview.getWidth(); new_height = Math.round(preview.getWidth()/ratio); } preview.setLayoutParams(new FrameLayout.LayoutParams(new_width, new_height)); 

El problema es realmente en la forma de las cosas de diseño. Hay overriden onLayout en la clase de Preview . Idea de su trabajo es establecer el tamaño de SurfaceView niño de acuerdo a Size óptimo encontrado. Pero no tiene en cuenta la rotación, por lo que necesita hacerlo por sí mismo:

  if (mPreviewSize != null) { previewWidth = mPreviewSize.height; previewHeight = mPreviewSize.width; } 

en lugar de

  if (mPreviewSize != null) { previewWidth = mPreviewSize.width; previewHeight = mPreviewSize.height; } 

El truco es intercambiar el ancho y la altura que se hace debido a la rotación de 90 grados alcanzada por

  mCamera.setDisplayOrientation(90); 

También puede considerar la configuración de tamaño de vista previa de bifurcación para niños dependiendo de la orientación que establezca

  public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { //... } 

(En proporcionado por mí código es siempre para la rotación de 90 grados, para 180 usted no tiene que hacer anyhing y cuando usted no fija ninguna rotación, no hay necesidad de intercambiar ancho y la altura)

Otra cosa digno de mencionar – al calcular getOptimalPreviewSize para el caso cuando usted tiene rotación y usted intercambia el ancho y la altura del niño usted también debe pasar el padre (la onMeasure ) el ancho y la altura intercambiados en onMeasure :

 if (mSupportedPreviewSizes != null) { //noinspection SuspiciousNameCombination final int previewWidth = height; //noinspection SuspiciousNameCombination final int previewHeight = width; mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, previewWidth, previewHeight); } 

Usando la solución anterior, usando el método private Size getOptimalPreviewSize (Tamaño de lista, int w, int h). Funcionó bien! Tenía problemas con la relación de aspecto en la orientación vertical: Aquí está mi solución usando. Mezcla con la documentación de android:

  public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { // If your preview can change or rotate, take care of those events here. // Make sure to stop the preview before resizing or reformatting it. if (mHolder.getSurface() == null){ // preview surface does not exist return; } // stop preview before making changes try { mCamera.stopPreview(); } catch (Exception e){ // ignore: tried to stop a non-existent preview } // set preview size and make any resize, rotate or // reformatting changes here Camera.Parameters params = mCamera.getParameters(); params.set("orientation", "portrait"); Size optimalSize=getOptimalPreviewSize(params.getSupportedPreviewSizes(), getResources().getDisplayMetrics().widthPixels, getResources().getDisplayMetrics().heightPixels); params.setPreviewSize(optimalSize.width, optimalSize.height); mCamera.setParameters(params); // start preview with new settings try { mCamera.setPreviewDisplay(mHolder); mCamera.startPreview(); } catch (Exception e){ Log.d(TAG, "Error starting camera preview: " + e.getMessage()); } } } 

La respuesta de Henric no funcionó para mí, así que he creado otro método que determina el tamaño de vista previa óptimo para cualquier cámara dada la vista de destino actual de ancho y altura y también la orientación de la actividad:

 public static Size getOptimalPreviewSize(List<Camera.Size> cameraPreviewSizes, int targetWidth, int targetHeight, boolean isActivityPortrait) { if (CommonUtils.isEmpty(cameraPreviewSizes)) { return null; } int optimalHeight = Integer.MIN_VALUE; int optimalWidth = Integer.MIN_VALUE; for (Camera.Size cameraPreviewSize : cameraPreviewSizes) { boolean isCameraPreviewHeightBigger = cameraPreviewSize.height > cameraPreviewSize.width; int actualCameraWidth = cameraPreviewSize.width; int actualCameraHeight = cameraPreviewSize.height; if (isActivityPortrait) { if (!isCameraPreviewHeightBigger) { int temp = cameraPreviewSize.width; actualCameraWidth = cameraPreviewSize.height; actualCameraHeight = temp; } } else { if (isCameraPreviewHeightBigger) { int temp = cameraPreviewSize.width; actualCameraWidth = cameraPreviewSize.height; actualCameraHeight = temp; } } if (actualCameraWidth > targetWidth || actualCameraHeight > targetHeight) { // finds only smaller preview sizes than target size continue; } if (actualCameraWidth > optimalWidth && actualCameraHeight > optimalHeight) { // finds only better sizes optimalWidth = actualCameraWidth; optimalHeight = actualCameraHeight; } } Size optimalSize = null; if (optimalHeight != Integer.MIN_VALUE && optimalWidth != Integer.MIN_VALUE) { optimalSize = new Size(optimalWidth, optimalHeight); } return optimalSize; } 

Esto utiliza un objeto de tamaño personalizado, ya que el tamaño de Android está disponible después de la API 21.

 public class Size { private int width; private int height; public Size(int width, int height) { this.width = width; this.height = height; } public int getHeight() { return height; } public int getWidth() { return width; } } 

Puede determinar el ancho y la altura de una vista escuchando sus cambios de diseño global y, a continuación, puede establecer las nuevas dimensiones. Esto también muestra cómo determinar la orientación de la actividad mediante programación:

 cameraPreviewLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { // gets called after layout has been done but before display. cameraPreviewLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this); boolean isActivityPortrait = getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT; Size optimalCameraPreviewSize = CustomUtils.getOptimalPreviewSize(cameraPreview.getCameraSizes(), cameraPreviewLayout.getWidth(), cameraPreviewLayout.getHeight(), isActivityPortrait); if (optimalCameraPreviewSize != null) { LinearLayout.LayoutParams cameraPreviewLayoutParams = new LinearLayout.LayoutParams(optimalCameraPreviewSize.getWidth(), optimalCameraPreviewSize.getHeight()); cameraPreviewLayout.setLayoutParams(cameraPreviewLayoutParams); } } }); 
  • Cámara Qt QML a C ++ QImage en Android
  • Uso de la API de Camera2 con ImageReader
  • RuntimeException en Camera.setParameters () en el nexo uno
  • Configurar el tamaño de la cámara - ¿Parámetros vs intención?
  • Problemas con el flash de la cámara Samsung Galaxy S5
  • Android ha desaprobado android.hardware.Camera y ahora recomendamos usar android.hardware.camera2 pero esto no está disponible en nada debajo de la API 21
  • La vista previa de la cámara se bloquea después del bloqueo de la pantalla
  • Capturar fotogramas de vista previa de Camera2 devuelve el búfer vacío
  • Obtener imagen de la cámara en ImageView Android
  • Cómo leer varios códigos qr de una imagen usando la biblioteca zxing
  • SetParameters () falla a pesar de configurar el tamaño de vista previa
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.