我对 OpenCV 的 Android 相机示例代码感到困惑。他们创建了一个自定义类,该类实现SurfaceHolder.Callback
并将以下行放入方法中surfaceChanged
:
mCamera.setPreviewDisplay(null);
setPreviewDisplay
用于解释的 Android 文档:
此方法必须在 startPreview() 之前调用。一个例外是,如果在调用 startPreview() 之前未设置预览表面(或设置为 null),则可以使用非 null 参数调用此方法一次以设置预览表面。(这允许相机设置和表面创建并行发生,节省时间。)预览表面可能不会在预览运行时更改。
不同寻常的是,OpenCV 的代码从不setPreviewDisplay
使用非空 SurfaceHolder 进行调用。它工作正常,但使用更改图像的旋转setDisplayOrientation
不起作用。这条线似乎也没有做任何事情,因为没有它我会得到相同的结果。
如果我setPreviewDisplay
使用提供给surfaceChanged
而不是SurfaceHolder 进行调用null
,则图像会旋转,但不包括图像处理的结果。稍后我也会收到一个IllegalArgumentException
电话lockCanvas
。
这是怎么回事?
以下是他们代码中(可能)最相关的部分,稍微简化并内联了方法。这是完整版。
类定义
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");
}