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