Android 使用ImageReader保存时camera2预览图像乱序

Android camera2 preview image disorder when saved using ImageReader

我正在使用 Android Camera2 API 拍摄一系列照片以进行实时姿势估计和环境重建(SLAM 问题)。目前我只是简单地将所有这些图片保存在我的 SD 卡中以供离线处理。

我根据 google 的 Camera2Basic 使用 TextureViewImageReader 设置处理管道,它们都设置为目标表面重复预览请求。

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是added/removed。 ImageReaderOnImageAvailableListener实现如下:

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)来丢弃旧帧,并且还检查了图像的时间戳以确保它们单调递增。

reader 确实以可接受的速率(约 25fps)接收图像。然而,仔细查看保存的图像序列会发现它们不是 总是按时间顺序保存。

以下图片来自程序拍摄的长序列(抱歉不能直接post图片:( ):

图片 1:

图 2:

图 3:

这种混乱不常发生,但随时可能发生,似乎不是初始化问题。我想这与 ImageReader 的缓冲区大小有关,因为缓冲区越大,"flash backs" 就更少。有人遇到同样的问题吗?

启用 ImageReader 时,您是使用 TEMPLATE_STILL_CAPTURE 进行捕获请求,还是仅使用 TEMPLATE_PREVIEW?您发现哪些设备有问题?

如果您使用的是 STILL_CAPTURE,请务必检查设备是否支持 ENABLE_ZSL 标志,并将其设置为 false。当它设置为 true 时(通常是支持它的设备的默认设置,对于 STILL_CAPTURE 模板),图像可能会乱序返回,因为相机设备中有一个零快门延迟队列。

我终于发现在其构造函数中将ImageReader的格式设置为YUV_420_888时,这种混乱消失了。本来我把这个字段设置为JPEG

使用JPEG格式,不仅处理延迟大,而且乱序。我猜从图像传感器数据到所需格式的转换利用了其他硬件,例如 DSP 或 GPU,这些硬件不能保证按时间顺序排列。