2012-09-03 21 views
8

Estoy haciendo una aplicación de realidad virtual donde la cámara debe detectar caras, localizarlas y mostrar su ubicación en la vista previa de la cámara.Android dibujar en cámara vista previa

Sé de 3 maneras de hacerlo, me gustaría utilizar GLSurfaceView a ser tan rápido como sea posible (according to this post), pero actualmente estoy tratando de dibujar en la misma SurfaceView donde la cámara está utilizando para su vista previa. Mi devolución de llamada para dibujar en ella sería onFaceDetection así:

public class MyActivity extends Activity implements SurfaceHolder.Callback, Camera.FaceDetectionListener { 
    Camera camera; 
    SurfaceView svPreview; 
    SurfaceHolder previewHolder; 
    TextView tvInfo; 
    Paint red; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main); 

     svPreview = (SurfaceView) findViewById(R.id.svPreview); 
     tvInfo = (TextView) findViewById(R.id.tvInfo); 

     red = new Paint(); 
     red.setStyle(Paint.Style.STROKE); 
     red.setStrokeWidth(3); 

     previewHolder = svPreview.getHolder(); 
     previewHolder.addCallback(this); 
     previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 
    } 

    public void surfaceCreated(SurfaceHolder arg0) { 
     camera = Camera.open(); 
     try { 
      camera.setDisplayOrientation(90); 
      camera.setFaceDetectionListener(this); 
      camera.setPreviewDisplay(previewHolder); 
     } 
     catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 

    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 
     // . . . 
     camera.startPreview(); 
     camera.autoFocus(null); 
     camera.startFaceDetection(); 
    } 

    public void surfaceDestroyed(SurfaceHolder arg0) { 
     camera.stopFaceDetection(); 
     camera.cancelAutoFocus(); 
     camera.stopPreview(); 
     camera.release(); 
     camera = null; 
    } 

    public void onFaceDetection(Face[] faces, Camera camera) { 
     tvInfo.setText("Faces: " + String.valueOf(faces.length)); 

     Canvas canvas = previewHolder.lockCanvas(); 
     for(int i=0; i < faces.length; i++) { 
      Point leftEye = faces[i].leftEye; 
      Point rightEye = faces[i].rightEye; 
      // this is not working 
      canvas.drawPoint(leftEye.x, leftEye.y, red); 
     } 
     previewHolder.unlockCanvasAndPost(canvas); 
    } 
} 

Con este código me siguen dando este error:

09-03 19:35:42.743: E/SurfaceHolder(19394): Exception locking surface 
09-03 19:35:42.743: E/SurfaceHolder(19394): java.lang.IllegalArgumentException 
09-03 19:35:42.743: E/SurfaceHolder(19394):  at android.view.Surface.lockCanvasNative(Native Method) 
09-03 19:35:42.743: E/SurfaceHolder(19394):  at android.view.Surface.lockCanvas(Surface.java:76) 
09-03 19:35:42.743: E/SurfaceHolder(19394):  at android.view.SurfaceView$4.internalLockCanvas(SurfaceView.java:744) 
09-03 19:35:42.743: E/SurfaceHolder(19394):  at android.view.SurfaceView$4.lockCanvas(SurfaceView.java:720) 
09-03 19:35:42.743: E/SurfaceHolder(19394):  at com.bluetooth.activities.MyActivity.onFaceDetection(MyActivity.java:90) 
09-03 19:35:42.743: E/SurfaceHolder(19394):  at android.hardware.Camera$EventHandler.handleMessage(Camera.java:729) 
09-03 19:35:42.743: E/SurfaceHolder(19394):  at android.os.Handler.dispatchMessage(Handler.java:99) 
09-03 19:35:42.743: E/SurfaceHolder(19394):  at android.os.Looper.loop(Looper.java:137) 
09-03 19:35:42.743: E/SurfaceHolder(19394):  at android.app.ActivityThread.main(ActivityThread.java:4424) 
09-03 19:35:42.743: E/SurfaceHolder(19394):  at java.lang.reflect.Method.invokeNative(Native Method) 
09-03 19:35:42.743: E/SurfaceHolder(19394):  at java.lang.reflect.Method.invoke(Method.java:511) 
09-03 19:35:42.743: E/SurfaceHolder(19394):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784) 
09-03 19:35:42.743: E/SurfaceHolder(19394):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551) 
09-03 19:35:42.743: E/SurfaceHolder(19394):  at dalvik.system.NativeStart.main(Native Method) 
09-03 19:35:42.743: W/dalvikvm(19394): threadid=1: thread exiting with uncaught exception (group=0x40a561f8) 
09-03 19:35:42.766: E/AndroidRuntime(19394): FATAL EXCEPTION: main 
09-03 19:35:42.766: E/AndroidRuntime(19394): java.lang.IllegalArgumentException 
09-03 19:35:42.766: E/AndroidRuntime(19394): at android.view.Surface.unlockCanvasAndPost(Native Method) 
09-03 19:35:42.766: E/AndroidRuntime(19394): at android.view.SurfaceView$4.unlockCanvasAndPost(SurfaceView.java:775) 
09-03 19:35:42.766: E/AndroidRuntime(19394): at com.bluetooth.activities.MyActivity.onFaceDetection(MyActivity.java:99) 
09-03 19:35:42.766: E/AndroidRuntime(19394): at android.hardware.Camera$EventHandler.handleMessage(Camera.java:729) 
09-03 19:35:42.766: E/AndroidRuntime(19394): at android.os.Handler.dispatchMessage(Handler.java:99) 
09-03 19:35:42.766: E/AndroidRuntime(19394): at android.os.Looper.loop(Looper.java:137) 
09-03 19:35:42.766: E/AndroidRuntime(19394): at android.app.ActivityThread.main(ActivityThread.java:4424) 
09-03 19:35:42.766: E/AndroidRuntime(19394): at java.lang.reflect.Method.invokeNative(Native Method) 
09-03 19:35:42.766: E/AndroidRuntime(19394): at java.lang.reflect.Method.invoke(Method.java:511) 
09-03 19:35:42.766: E/AndroidRuntime(19394): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784) 
09-03 19:35:42.766: E/AndroidRuntime(19394): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551) 
09-03 19:35:42.766: E/AndroidRuntime(19394): at dalvik.system.NativeStart.main(Native Method) 

¿Hay un problema con la cámara tratando de llamar su vista previa en la misma SurfaceView la devolución de llamada de detección de rostros? ¿Cómo puedo hacer esto sin superponer SurfaceViews?

+0

He añadido una recompensa a esto porque al cavar en la fuente de Android parece que la vista previa se ejecuta en un hilo diferente que el resto de la aplicación, lo que creo que significa que su aplicación no puede obtener un objeto Canvas o bloqueo la superficie, porque son hilos diferentes. Dicho esto, espero que alguien que haya respondido esto responda –

+0

¿Qué le parece usar un FrameLayout en la parte superior de todas estas vistas con un fondo transparente? – Shafi

Respuesta

6

No se puede hacer clic y dibujar en un SurfaceView que tiene Type.PUSH_BUFFERS, (en el que se muestran los marcos). Tienes que crear otra vista por encima de la original en la dirección Z y dibujar en una vista de superficie en esa vista.

Por lo tanto, en su main.xml cree una vista personalizada debajo de su vista original en un FrameLayout.

Cree y maneje un SurfaceView en su Vista de actividad. Agregue esta vista a la pantalla de vista previa de la cámara. Comience su vista personalizada pasando el SurfaceHolder. En esta vista puede bloquear y dibujar en un lienzo.

-1

pude dicho,

No se trata de un hilo.

No es debido a esta línea que comete un error tampoco.

canvas.drawPoint(leftEye.x, leftEye.y, red); 

Es a causa de la lona de dejar de utilizar y no puede bloquearlo

Si marca con cuidado, verá este lienzo que se obtiene es == null

canvas = canvasHolder.lockCanvas(); 
    if (canvas == null) Log.i("Error", "Canvas == null!"); 

Es posible que tenga pregunta, ¿dónde está ya usado?

¡Ya se utiliza para mostrar para mostrar lo que te está pasando! Es decir

camera.setPreviewDisplay(previewHolder); 

Por lo tanto, sugiero, si desea dibujar el punto sobre el ojo, puede que tenga que tener otro SurfaceView/SurfaceHolder sobre ti SurfaceView para la cámara previsualización:]

5

Como James señaló que necesitará crear la superficie a medida que se extiende SurfaceView (por lo general implemento SurfaceHolder.Callback también):

public class CameraSurfacePreview extends SurfaceView implements SurfaceHolder.Callback

Constructor será algo como:

public CameraSurfacePreview(Context context) { 
    super(context); 
    ... 
    mHolder = getHolder(); 
    mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 
    ... 

Debe unir la cámara a su superficie después de la llamada abierta de la cámara (si implementa implementa SurfaceHolder).Devolución de llamada poner esto en algún lugar dentro surfaceCreated anulado):

mCamera = Camera.open(); 
mCamera.setPreviewDisplay(mHolder); 

Por último es necesario agregar instancia de su somehere superficie costumbre en vista del contenido de actividad:

CameraSurfacePreview cameraSurfacePreview = new CameraSurfacePreview(this); 
//camera surface preview is first child! 
((ViewGroup)findViewById(R.id.cameraLayout)).addView(cameraSurfacePreview, 0); 

En mi ejemplo de diseño para la actividad se ve algo así como (I estoy mostrando previa de la cámara en el diseño de marco principal):

<?xml version="1.0" encoding="utf-8"?> 
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
       android:layout_width="fill_parent"   
         android:layout_height="fill_parent" 
       android:layout_gravity="top|left" 
       android:id="@+id/cameraLayout"> 
0

el enfoque lockcanvas/unlockcanvasandpost no es apropiado cuando se utiliza openGL como la opa El código nGL controla y bloquea la superficie. Si desea utilizar las API 2d estándar, no use OpenGL.

Cuestiones relacionadas