Добавление ImageReader с более высоким разрешением искажает предварительный просмотр и результат ImageReader - PullRequest
0 голосов
/ 26 июня 2019

При использовании API Camera2 на устройстве Samsung J6 и добавлении ImageReader к выходу камеры предварительный просмотр становится перекошенным, а также изображение, полученное в ImageReader.onImageAvailable, перекошается.

Например, если я использую 960x720 в качестве разрешения для предварительного просмотра (отношение пикселей 1: 1 к размеру экрана) и 960x720 для ImageReader, проблем нет, все изображения выглядят хорошо, и распознавание лиц также работает. Однако если я установлю разрешение ImageReader на 2048x1536 (для лучшего качества обработки), изображение для предварительного просмотра будет выглядеть как обрезанное до 16: 9, а затем расширено до 4: 3, чтобы соответствовать размеру предварительного просмотра. То же самое с изображением в ImageReader.onImageAvailable.

https://i.ibb.co/zPbTGJ3/ss1.jpg https://i.ibb.co/McbL93k/ss2.jpg

Также обнаружение лица кажется неправильным, так как оно возвращает максимальные координаты, когда лицо находится только в центре вида (SENSOR_INFO_ACTIVE_ARRAY_SIZE равно 4144x3106).

https://i.ibb.co/6wtP5qS/ss3.jpg

Это нормально работает на устройствах с более высокими характеристиками, таких как Galaxy S7, S8, S9, A8 и т. Д., Но я заметил, что оно не работает нормально на устройствах Samsung J5 или J6.

Вот мой код SurfaceTextureListener:

    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
        try {
            if(useCamera2API) {
                mCameraManager = (CameraManager) context.getSystemService(CAMERA_SERVICE);
                String[] cameraList = mCameraManager.getCameraIdList();

                if(cameraList.length == 0) {
                    return;
                }

                mCameraCharacteristics = mCameraManager.getCameraCharacteristics(cameraList[0]);

                mMaxCameraSize = new Rectangle(mCameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE)).size;
                nativeRatio = mMaxCameraSize.width / mMaxCameraSize.height;

                height = (int)(width * nativeRatio);

                VCamera.getLayoutParams().height = height;

                mScreenSize = new Size(height, width);

                StreamConfigurationMap map = mCameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);

                if (map != null) {
                    Size[] previewSizes = Size.castSizes(map.getOutputSizes(SurfaceTexture.class));
                    Size[] yuvSizes = Size.castSizes(map.getOutputSizes(ImageFormat.YUV_420_888));

                    // this gets the smallest size closest to maximum camera size ratio while keeping both dimensions above 1000 pixels
                    mCameraSize = Helper.getSmallestSize(yuvSizes, 1000, nativeRatio);
                    // this gets size that is closest to 1:1 pixel ratio to screen
                    mPreviewSize = Helper.getOptimalPreviewSize(previewSizes, height, width);

                    log(String.format("%d %d, %d %d", (int) mCameraSize.width, (int) mCameraSize.height, (int) mPreviewSize.width, (int) mPreviewSize.height));

                    supportsAEAreas = mCameraCharacteristics.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AE) > 0;
                    supportsAFAreas = mCameraCharacteristics.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AF) > 0;

                    mPreviewImageReader = ImageReader.newInstance((int) mCameraSize.getWidth(), (int) mCameraSize.getHeight(), ImageFormat.YUV_420_888, 1);

И код CameraDevice.StateCallback:

CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {

    @Override
    public void onOpened(@NonNull CameraDevice camera) {
        Log.d(LOG_TAG, "Camera opened.");

        mCameraDevice = camera;

        SurfaceTexture texture = VCamera.getSurfaceTexture();

        if (texture == null) {
            return;
        }

        texture.setDefaultBufferSize((int) mPreviewSize.getWidth(), (int) mPreviewSize.getHeight());

        Surface surface = new Surface(texture);

        try {
            mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);

            List<Surface> surfaces = new ArrayList<>();

            mPreviewBuilder.addTarget(surface);
            surfaces.add(surface);

            mPreviewBuilder.addTarget(mPreviewImageReader.getSurface());
            surfaces.add(mPreviewImageReader.getSurface());

            backgroundThread = new HandlerThread("CameraPreview");
            backgroundThread.start();
            backgroundHandler = new Handler(backgroundThread.getLooper());

            mPreviewImageReader.setOnImageAvailableListener(mImageAvailableListener, backgroundHandler);

            mCameraDevice.createCaptureSession(surfaces, previewStateCallback, null);

            if(mode == CameraRequestMode.BARCODE_CONTINUOUS) {
                delegate.cameraContinuousStarted();
            }

Я бы ожидал, что хотя бы предварительный просмотр будет выглядеть нормально. Есть ли какая-то конфигурация, которую мне не хватает? Я где-то видел информацию, что Camera2 API просто не работает на некоторых устройствах. Я бы отказался от старого API камеры, если бы было возможно получить кадры с более высоким разрешением, чем предварительный просмотр (возможно, но не так легко достижимо). Я застрял, просто используя разрешение 960x720 для обработки изображений?

...