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?

Solutions Collecting From Web of "Android上画相机预览"

你不能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预览相机:]