SetPreviewDisplay y setDisplayOrientation

Estoy sorprendido por el código de ejemplo de la cámara Android de OpenCV. Ellos hacen una clase personalizada que implementa SurfaceHolder.Callback y poner la siguiente línea dentro del método surfaceChanged :

 mCamera.setPreviewDisplay(null); 

La documentación de Android de setPreviewDisplay explica:

Este método debe ser llamado antes de startPreview (). La única excepción es que si la superficie de vista previa no se establece (o se establece en nulo) antes de que startPreview () se llame, este método se puede llamar una vez con un parámetro no nulo para establecer la superficie de vista previa. (Esto permite que la configuración de la cámara y la creación de la superficie ocurran en paralelo, ahorrando tiempo.) La superficie de vista previa no puede cambiar de otra forma mientras se está ejecutando la vista previa.

Inusualmente, el código de OpenCV nunca llama a setPreviewDisplay con un setPreviewDisplay no nulo. Funciona bien, pero cambiar la rotación de la imagen usando setDisplayOrientation no funciona. Esta línea tampoco parece hacer nada, ya que obtengo los mismos resultados sin él.

Si llamo setPreviewDisplay con SurfaceHolder suministrado a surfaceChanged lugar de null , la imagen gira, pero no incluye los resultados del procesamiento de la imagen. También recibo una IllegalArgumentException al llamar a lockCanvas más adelante.

¿Que esta pasando?

Aquí están las partes (posiblemente) más relevantes de su código, ligeramente simplificado y con métodos inline. Aquí está la versión completa .

Definición de clase

 public abstract class SampleViewBase extends SurfaceView implements SurfaceHolder.Callback, Runnable { 

Cuando se abre la cámara

 mCamera.setPreviewCallbackWithBuffer(new PreviewCallback() { public void onPreviewFrame(byte[] data, Camera camera) { synchronized (SampleViewBase.this) { System.arraycopy(data, 0, mFrame, 0, data.length); SampleViewBase.this.notify(); } camera.addCallbackBuffer(mBuffer); } }); 

Cuando la superficie cambia

 /* Now allocate the buffer */ mBuffer = new byte[size]; /* The buffer where the current frame will be copied */ mFrame = new byte [size]; mCamera.addCallbackBuffer(mBuffer); try { mCamera.setPreviewDisplay(null); } catch (IOException e) { Log.e(TAG, "mCamera.setPreviewDisplay/setPreviewTexture fails: " + e); } [...] /* Now we can start a preview */ mCamera.startPreview(); 

El método run

 public void run() { mThreadRun = true; Log.i(TAG, "Starting processing thread"); while (mThreadRun) { Bitmap bmp = null; synchronized (this) { try { this.wait(); bmp = processFrame(mFrame); } catch (InterruptedException e) { e.printStackTrace(); } } if (bmp != null) { Canvas canvas = mHolder.lockCanvas(); if (canvas != null) { canvas.drawBitmap(bmp, (canvas.getWidth() - getFrameWidth()) / 2, (canvas.getHeight() - getFrameHeight()) / 2, null); mHolder.unlockCanvasAndPost(canvas); } } } Log.i(TAG, "Finishing processing thread"); } 

Me encontré con el mismo problema. En lugar de usar un SurfaceView.Callback , subclase su clase JavaCameraView . Ver mi detección de cara en vivo y muestra de dibujo aquí . Entonces era trivial girar la matriz que salía de la cámara de acuerdo con la orientación del dispositivo, antes de procesarla. Extracto pertinente del código vinculado:

 @Override public Mat onCameraFrame(Mat inputFrame) { int flipFlags = 1; if(display.getRotation() == Surface.ROTATION_270) { flipFlags = -1; Log.i(VIEW_LOG_TAG, "Orientation is" + getRotation()); } Core.flip(inputFrame, mRgba, flipFlags); inputFrame.release(); Imgproc.cvtColor(mRgba, mGray, Imgproc.COLOR_RGBA2GRAY); if (mAbsoluteFaceSize == 0) { int height = mGray.rows(); if (Math.round(height * mRelativeFaceSize) > 0) { mAbsoluteFaceSize = Math.round(height * mRelativeFaceSize); } } } 

Resolví el problema de rotación con OpenCV: después de averiguar cuánto necesita corregir la rotación de la pantalla usando este código , aplico una matriz de rotación a la imagen de la cámara en bruto (después de convertir de YUV a RGB):

 Point center = new Point(mFrameWidth/2, mFrameHeight/2); Mat rotationMatrix = Imgproc.getRotationMatrix2D(center, totalRotation, 1); 

[…]

 Imgproc.cvtColor(mYuv, mIntermediate, Imgproc.COLOR_YUV420sp2RGBA, 4); Imgproc.warpAffine(mIntermediate, mRgba, rotationMatrix, new Size(mFrameHeight, mFrameWidth)); 

Un problema aparte es que setPreviewDisplay(null) da una pantalla en blanco en algunos teléfonos. La solución, que he obtenido de aquí y se basa en este reporte de errores y esta pregunta SO, pasa un SurfaceView ocultado, "falso" a la pantalla de vista previa para que comience, pero en realidad muestra la salida en una vista personalizada superpuesta, que yo llamo Vista de cámara. Por lo tanto, después de llamar a setContentView() en la actividad onCreate() , se adhieren a este código:

 if (VERSION.SDK_INT < VERSION_CODES.HONEYCOMB) { final SurfaceView fakeView = new SurfaceView(this); fakeView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); fakeView.setZOrderMediaOverlay(false); final CameraView cameraView = (CameraView) this.findViewById(R.id.cameraview); cameraView.setZOrderMediaOverlay(true); cameraView.fakeView = fakeView; } 

A continuación, al configurar la vista preliminar, utilice este código:

 try { if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) mCamera.setPreviewTexture(new SurfaceTexture(10)); else mCamera.setPreviewDisplay(fakeView.getHolder()); } catch (IOException e) { Log.e(TAG, "mCamera.setPreviewDisplay fails: "+ e); } 

Si sólo está desarrollando para Honeycomb y superiores, simplemente reemplace setPreviewDisplay (null) con mCamera.setPreviewTexture(new SurfaceTexture(10)); Y hacerse con ella. setDisplayOrientation() todavía no funciona si lo hace, sin embargo, por lo que todavía tendrá que utilizar la solución de matriz de rotación.

  • Cámara de cualquier emulador que no funciona
  • Cómo burlar una imagen en Android Emulator Camera?
  • Guardar la imagen capturada en la carpeta específica de la tarjeta sd
  • La superficie de vista previa no válida de grabación de vídeo android
  • Android Moto X 4.2.2 Cámara FaceDetectionListener onFaceDetection () nunca llamado
  • Rotación de la matriz de bytes de JPEG después de onPictureTaken
  • Problema de cierre de cámara en Samsung Galaxy S3 versión 4.1.1
  • Takepicture se bloquea en Android 2.3.3
  • ¿Dónde puedo obtener el código fuente de la aplicación de cámara Android?
  • Camera.release () tarda 30 segundos en liberar la cámara en Nexus 10. ¿Hay alguna forma de acelerar el proceso?
  • Android MediaCodec y la cámara: ¿cómo lograr una mayor velocidad de fotogramas para obtener datos de marco de la cámara?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.