Android上画相机预览

我正在制作一个虚拟现实应用程序,在这个应用程序中,相机应该检测到脸部,find它们并在相机预览中显示它们的位置

我知道有3种方法可以做到这一点,我想使用GLSurfaceView尽可能快( 根据这篇文章 ),但目前我正在尝试使用相机用于预览的同一个 SurfaceView。 我的callback就是onFaceDetection就像这样:

 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); } } 

有了这个代码,我不断收到这个错误:

 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) 

相机试图在相同的SurfaceView上进行人脸检测callback时出现问题吗? 我怎样才能做到这一点没有分层SurfaceViews?

  • 对正在播放的video应用效果
  • android视图或surfaceView,我应该使用?
  • 如何在Android上正确使用setZOrderMediaOverlay?
  • 以编程方式在后台具有GL视图的软键盘上的EditText
  • 我怎样才能把一个透明的背景glSurfaceView的顶部视图?
  • 我如何使用Android的“表面”类?
  • 如何在同一个布局中使用多个GLSurfaceView组件?
  • Android视图与SurfaceView vs GLSurfaceView的2D绘图应用程序与Zoomable用户界面
  • 你不能locK和绘制有Type.PUSH_BUFFERS,(你正在显示帧)的SurfaceView。 您必须在Z方向上创build另一个视图,然后在该视图中绘制一个SurfaceView。

    所以在你的main.xml中在你的原始视图的FrameLayout下创build一个自定义的视图。

    在活动视图中创build和处理一个SurfaceView。 将此视图添加到相机预览显示。 开始传递SurfaceHolder的自定义视图。 在这个视图中可以locking和画在canvas上。

    正如James指出的那样,您需要创build自定义曲面来扩展SurfaceView(我通常还实现了SurfaceHolder.Callback):

    public class CameraSurfacePreview extends SurfaceView implements SurfaceHolder.Callback

    构造函数将如下所示:

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

    在摄像头打开调用之后,需要将摄像头与摄像头绑定(如果您实现的是SurfaceHolder.Callback,则将其放置在覆盖的surfaceCreated内):

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

    最后,您需要在活动内容视图中添加自定义表面的实例:

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

    在我的例子活动布局看起来像(我在主框架布局中显示相机预览):

     <?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"> 

    lockcanvas / unlockcanvasandpost方法不适合使用openGL,因为openGL代码正在控制和locking曲面。 如果你想使用标准的2D API,不要使用OpenGL。

    我可以说,

    这不是一个线程。

    这也不是因为这条线而造成错误。

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

    这是因为canvas仍在使用,无法locking

    如果仔细检查,你会看到你得到的这个canvas是== null

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

    您可能有问题,那么它在哪里使用?

    它已经用来显示,以显示你正在发生什么! 那是

     camera.setPreviewDisplay(previewHolder); 

    所以,我build议,如果你想画点在你的眼睛,你可能需要有另一个SurfaceView / SurfaceHolder你SurfaceView预览相机:]