簡體   English   中英

如何在Android5.0中實時使用camera2 API獲取每個幀數據

[英]How to get each frame data using camera2 API in Android5.0 in realtime

我現在正在使用camera2Basic並試圖讓每個幀數據進行一些圖像處理。 我在Android5.0中使用camera2 API,當只進行相機預覽並且它是流暢的時候一切都很好。 但是當我使用ImageReader.OnImageAvailableListener回調來獲取每個幀數據時,預覽會ImageReader.OnImageAvailableListener ,這會導致糟糕的用戶體驗。 以下是我的相關代碼:

這是攝像頭和ImageReader的設置,我設置的圖像格式是YUV_420_888

public<T> Size setUpCameraOutputs(CameraManager cameraManager,Class<T> kClass, int width, int height) {
    boolean flagSuccess = true;
    try {
        for (String cameraId : cameraManager.getCameraIdList()) {
            CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId);
            // choose the front or back camera
            if (FLAG_CAMERA.BACK_CAMERA == mChosenCamera &&        
                    CameraCharacteristics.LENS_FACING_BACK != characteristics.get(CameraCharacteristics.LENS_FACING)) {
                continue;
            }
            if (FLAG_CAMERA.FRONT_CAMERA == mChosenCamera &&  
                    CameraCharacteristics.LENS_FACING_FRONT != characteristics.get(CameraCharacteristics.LENS_FACING)) {
                continue;
            }
            StreamConfigurationMap map = characteristics.get(
                    CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);

            Size largestSize = Collections.max(
                    Arrays.asList(map.getOutputSizes(ImageFormat.YUV_420_888)),
                    new CompareSizesByArea());

            mImageReader = ImageReader.newInstance(largestSize.getWidth(), largestSize.getHeight(),
                    ImageFormat.YUV_420_888, 3);

            mImageReader.setOnImageAvailableListener(mOnImageAvailableListener, mBackgroundHandler);
            ...
            mCameraId = cameraId;
       }
    } catch (CameraAccessException e) {
        e.printStackTrace();
    } catch (NullPointerException e) {

    }
    ......
}

當相機成功打開時,我創建一個CameraCaptureSession進行相機預覽

private void createCameraPreviewSession() {
    if (null == mTexture) {
        return;
    }

    // We configure the size of default buffer to be the size of camera preview we want.
    mTexture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());

    // This is the output Surface we need to start preview
    Surface surface = new Surface(mTexture);

    // We set up a CaptureRequest.Builder with the output Surface.
    try {
        mPreviewRequestBuilder =
                mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
        mPreviewRequestBuilder.addTarget(mImageReader.getSurface());
        mPreviewRequestBuilder.addTarget(surface);

        // We create a CameraCaptureSession for camera preview
        mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),
                new CameraCaptureSession.StateCallback() {

                    @Override
                    public void onConfigured(CameraCaptureSession session) {
                        if (null == mCameraDevice) {
                            return;
                        }

                        // when the session is ready, we start displaying the preview
                        mCaptureSession = session;

                        // Finally, we start displaying the camera preview
                        mPreviewRequest = mPreviewRequestBuilder.build();
                        try {
                            mCaptureSession.setRepeatingRequest(mPreviewRequest,
                                    mCaptureCallback, mBackgroundHandler);
                        } catch (CameraAccessException e) {
                            e.printStackTrace();
                        }
                    }

                    @Override
                    public void onConfigureFailed(CameraCaptureSession session) {

                    }
                }, null);
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }
}

最后一個是ImageReader.OnImageAvailableListener回調

private final ImageReader.OnImageAvailableListener mOnImageAvailableListener = new ImageReader.OnImageAvailableListener() {
            @Override
            public void onImageAvailable(ImageReader reader) {
                Log.d(TAG, "The onImageAvailable thread id: " + Thread.currentThread().getId());
                Image readImage = reader.acquireLatestImage();
                readImage.close();
            }
        };

也許我做錯了設置,但我嘗試了幾次,但它不起作用。 也許有另一種獲取幀數據的方法而不是ImageReader,但我不知道。 有誰知道如何實時獲取每個幀數據?

我不相信陳是正確的。 圖像格式對我測試的設備的速度幾乎沒有影響。 相反,問題似乎與圖像大小有關。 在圖像格式為YUV_420_888的Xperia Z3 Compact上,我在StreamConfigurationMapgetOutputSizes方法中提供了許多不同的選項:

[1600x1200, 1280x720, 960x720, 720x480, 640x480, 480x320, 320x240, 176x144]

對於這些相應的尺寸,最大FPS我得到的設置時mImageReader.getSurface()作為目標mPreviewRequestBuilder是:

[13, 18, 25, 28, 30, 30, 30, 30 ]

因此,一種解決方案是使用較低的分辨率來實現您想要的速率。 對於好奇......請注意,這些時間似乎不受線路的影響

    mPreviewRequestBuilder.addTarget(surface);
...
    mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),

我擔心在屏幕上添加表面可能會增加開銷,但如果我刪除第一行並將第二行更改為

    mCameraDevice.createCaptureSession(Arrays.asList(mImageReader.getSurface()),

然后我看到時間變化小於1 fps。 因此,您是否也在屏幕上顯示圖像似乎並不重要。

我認為在camera2 API或ImageReader的框架中只有一些開銷,這使得無法獲得TextureView明顯獲得的全部速率。

最令人失望的事情之一是,如果您切換回不推薦使用的Camera API,您可以通過Camera.setPreviewCallbackWithBuffer方法設置PreviewCallback ,輕松獲得30 fps。 使用該方法,無論分辨率如何,我都能獲得30fps。 具體來說,雖然它不直接提供1600x1200,但它確實提供1920x1080,甚至是30fps。

我正在嘗試相同的事情,我想你可能會改變格式

mImageReader = ImageReader.newInstance(largestSize.getWidth(),
                                       largestSize.getHeight(),
                                       ImageFormat.FLEX_RGB_888, 3);

因為使用YUV可能會導致CPU壓縮數據,並且可能需要一些時間。 RGB可以直接顯示在設備上。 並且從圖像中檢測到臉部應該放入其他線程中你必須知道它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM