11

カメラが顔を検出し、それらを見つけて、カメラのプレビューにその場所を表示する仮想現実アプリケーションを作成しています。

私はそれを行う3つの方法を知っています.GLSurfaceViewを使用してできるだけ高速にしたいのですが(この投稿によると)、現在、カメラがプレビューに使用しているのと同じSurfaceViewに描画しようとしています. それを描画するための私のコールバックは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 でプレビューを描画しようとするカメラに問題はありますか? SurfaceView をレイヤー化せずにこれを行うにはどうすればよいですか?

4

4 に答える 4

8

SurfaceViewを持っているType.PUSH_BUFFERSもの(フレームを表示しているもの)をロックして描画することはできません。元のビューの上にZ方向に別のビューを作成し、そのビューを描画するSurfaceView必要がありViewます。

したがって、でmain.xml元のビューの下にカスタムビューを作成しますFrameLayout

SurfaceViewアクティビティビューでを作成して処理します。このビューをカメラプレビュー表示に追加します。を渡してカスタムビューを開始しますSurfaceHolder。このビューでは、キャンバスをロックして描画できます。

于 2012-09-24T12:38:52.030 に答える
6

James が指摘したように、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">
于 2012-09-26T17:23:10.350 に答える
0

openGL コードがサーフェスを制御およびロックしているため、openGL を使用する場合、lockcanvas/unlockcanvasandpost アプローチは適切ではありません。標準の 2d API を使用する場合は、OpenGL を使用しないでください。

于 2012-09-27T15:49:12.490 に答える
0

私は言うことができました、

それはスレッドについてではありません。

この行が原因でエラーが発生するわけでもありません。

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

キャンバスがまだ使用されており、ロックできないためです

注意深く確認すると、取得したこのキャンバスが == null であることがわかります

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

どこですでに使用されているのでしょうか?

何が起こっているかを表示するためにすでに使用されています。あれは

camera.setPreviewDisplay(previewHolder);

したがって、目の上にポイントを描きたい場合は、プレビューカメラ用にSurfaceViewの上に別のSurfaceView / SurfaceHolderが必要になる場合があります:]

于 2012-09-26T03:25:52.447 に答える