我正在使用Android Camera2 API拍摄一系列照片,用于实时姿势估计和环境重建(SLAM问题)。目前我只是将所有这些图片保存在我的SD卡中进行离线处理。
我根据谷歌的Camera2Basic
使用TextureView
以及ImageReader
设置处理管道,它们都被设置为重复预览请求的目标表面。
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(mIsShooting){
try {
mCaptureSession.stopRepeating();
mPreviewRequestBuilder.removeTarget(mImageReader.getSurface());
mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), mCaptureCallback, mBackgroundHandler);
mIsShooting = false;
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
else{
try {
mCaptureSession.stopRepeating();
mPreviewRequestBuilder.addTarget(mImageReader.getSurface());
mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), mCaptureCallback, mBackgroundHandler);
mIsShooting = true;
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
}
});
按下按钮时添加/删除ImageReader
。 ImageReader
的OnImageAvailableListener
实施如下:
private ImageReader.OnImageAvailableListener mOnImageAvailableListener = new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader reader) {
Image img = reader.acquireLatestImage();
if(null == img){
return;
}
if(img.getTimestamp() <= mLatestFrameTime){
Log.i(Tag, "disorder detected!");
return;
}
mLatestFrameTime = img.getTimestamp();
ImageSaver saver = new ImageSaver(img, img.getTimestamp());
saver.run();
}
};
我使用acquireLatestImage
(缓冲区大小设置为2)来丢弃旧帧,并检查图像的时间戳以确保它们单调增加。
读者确实以可接受的速率(约25fps)接收图像。但仔细观察保存的图像序列表明它们并不总是按时间顺序保存。
以下图片来自程序拍摄的长序列(抱歉无法直接发布图片:():
图1:
图2:
图3:
这种病症不会经常发生,但它们可以随时发生,似乎不是初始化问题。我认为它与ImageReader
的缓冲区大小有关,因为更大的缓冲区更少发生“闪回”。有没有人有同样的问题?
您是否在启用ImageReader时使用TEMPLATE_STILL_CAPTURE进行捕获请求,或者仅使用TEMPLATE_PREVIEW?您看到哪些设备存在问题?
如果您正在使用STILL_CAPTURE,请确保检查设备是否支持ENABLE_ZSL标志,并将其设置为false。当它设置为true时(通常是支持它的设备上的默认值,对于STILL_CAPTURE模板),图像可能无序返回,因为在相机设备中有一个零快门滞后队列。
我终于发现,当ImageReader
的格式在其构造函数中为YUV_420_888
时,这种混乱就会消失。最初我把这个字段设为JPEG
。
使用JPEG
格式不仅会导致大的处理延迟,还会导致无序。我想从图像传感器数据到所需格式的转换利用其他硬件,如DSP或GPU,不保证按时间顺序排列。