我对OpenCV的Android相机示例代码感到困惑。他们创建了一个实现SurfaceHolder.Callback的自定义类,并将以下行放入surfaceChanged方法中:

mCamera.setPreviewDisplay(null);
setPreviewDisplay的Android文档说明:



通常,OpenCV的代码永远不会使用非null的SurfaceHolder调用setPreviewDisplay。它工作正常,但是使用setDisplayOrientation更改图像的旋转不起作用。该行似乎也没有执行任何操作,因为如果没有它,我将得到相同的结果。

如果我使用提供给setPreviewDisplay而不是surfaceChanged的SurfaceHolder调用null,则图像会旋转,但不包括图像处理的结果。稍后再调用IllegalArgumentException时,我也会得到一个lockCanvas

这是怎么回事?

这是其代码中(可能)最相关的部分,略有简化,并内联了方法。这是the full version

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

打开相机时
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);
    }
});

当表面改变时
/* 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();

运行方法
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");
}

最佳答案

我遇到了同样的问题。我没有使用SurfaceView.Callback,而是将它们的类JavaCameraView继承了子类。请参阅我的活脸检测和绘画示例here。然后,在处理之前,根据设备的方向旋转从相机出来的矩阵很简单。链接代码的相关摘录:

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

关于android - setPreviewDisplay和setDisplayOrientation,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/15562481/

10-08 21:01