我正在捕捉一个图像使用CameraX在android的按钮点击,但在一些手机捕捉的图像是旋转的,为什么会这样,如何纠正它?

8dtrkrch  于 2023-02-17  发布在  Android
关注(0)|答案(1)|浏览(238)

我捕捉图像是为了把它转换成一定大小的正方形。当我使用不同的手机捕捉图像时,在其中一些手机中捕捉到的图像与预览中显示的图像相同,但在一些手机中,捕捉到的图像是旋转的。
下面是代码:
按钮点击:

bGetImage.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                final Bitmap[] bitmap = {null};
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
                    imageCapture.takePicture(getMainExecutor(),new ImageCapture.OnImageCapturedCallback() {
                        @Override
                        public void onCaptureSuccess(@NonNull ImageProxy image) {
                            super.onCaptureSuccess(image);
                            Log.d(TAG, "onCaptureSuccess: testview.innerRectangle " + testview.innerRectangle.width());
                            Log.d(TAG, "onCaptureSuccess: testview.innerRectangle " + testview.innerRectangle.height());
                            OutputTransform source = previewView.getOutputTransform();
                            // imageProxy is the output of the ImageCapture.
                            OutputTransform target = new ImageProxyTransformFactory().getOutputTransform(image);
                            //print size of target
                            Log.d(TAG, "onCaptureSuccess: target " + target.getMatrix().toString());
                            // Build the transform from ImageAnalysis to PreviewView
                            CoordinateTransform coordinateTransform = new CoordinateTransform(source, target);
                            // The variable box here is your bounding box in PreviewView
                            coordinateTransform.mapRect(testview.innerRectangle);

                            Log.d(TAG, "onCaptureSuccess: testview.innerRectangle " + testview.innerRectangle.width());
                            Log.d(TAG, "onCaptureSuccess: testview.innerRectangle " + testview.innerRectangle.height());
                            bitmap[0] = imageProxytoBitmap(image);
                            Log.d(TAG, "onCaptureSuccess: bitmap[0] " + bitmap[0].getWidth());
                            Log.d(TAG, "onCaptureSuccess: bitmap[0] " + bitmap[0].getHeight());

//                            bitmap[0] = Bitmap.createBitmap(bitmap[0],(int)testview.innerRectangle.left,(int)testview.innerRectangle.top,(int)testview.innerRectangle.width(),(int)testview.innerRectangle.height());

                            try {
                                Uri uri = getUri(bitmap[0], getContentResolver());
                                Log.d(TAG, "onCaptureSuccess: bitmap[0] " + bitmap[0].getWidth());
                                Log.d(TAG, "onCaptureSuccess: bitmap[0] " + bitmap[0].getHeight());
                                String path = uri.toString();
                                moveToScanActivity(path);
                            } catch (IOException e) {
                                Log.e(TAG, "onCaptureSuccess: ",e);
                            }
                        }
                    });
                }

            }
        });

摄像头提供程序初始化:

cameraProviderFuture.addListener(() -> {
            try {
                ProcessCameraProvider cameraProvider = cameraProviderFuture.get();

                CameraSelector selector = CameraSelector.DEFAULT_BACK_CAMERA;

                cameraProvider.unbindAll();
//                Camera camera = cameraProvider.bindToLifecycle(this, selector);

                bindPreview(cameraProvider);
            } catch (ExecutionException | InterruptedException e) {
                // No errors need to be handled for this Future.
                // This should never be reached.
            }

        }, ContextCompat.getMainExecutor(this));

我正在使用的其他功能:

void bindPreview(@NonNull ProcessCameraProvider cameraProvider) {
        Log.d(TAG, "bindPreview: width " + width);
        Log.d(TAG, "bindPreview: height " + height);
        Preview preview = new Preview.Builder()
                .setTargetResolution(new Size(width, height))
                .setTargetRotation(ROTATION_0)
                .build();

        previewView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
            @Override
            public void onLayoutChange(
                    View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
                Size newViewFinderDimens = new Size(right - left, bottom - top);
                updateTransform(0, MainActivity.bufferDimens, newViewFinderDimens);
            }
        });

         imageCapture =
                new ImageCapture.Builder()
                        .setTargetResolution(new Size(width, height))
                        .setTargetRotation(ROTATION_0)
                        .build();

        CameraSelector cameraSelector = new CameraSelector.Builder()
                .requireLensFacing(CameraSelector.LENS_FACING_BACK)
                .build();

        preview.setSurfaceProvider(previewView.getSurfaceProvider());

        UseCaseGroup useCaseGroup = new UseCaseGroup.Builder()
                .addUseCase(preview)
                .addUseCase(imageCapture)
                .build();

        cameraProvider.bindToLifecycle((LifecycleOwner)this, cameraSelector, useCaseGroup);

        previewHeight = previewView.getHeight();
        previewWidth = previewView.getWidth();
    }
private Uri getUri(Bitmap bitmap, ContentResolver contentResolver) throws FileNotFoundException {
        File file = new File(getApplicationContext().getExternalMediaDirs()[0].getAbsolutePath(),"Mytittle_" + System.currentTimeMillis() + ".png");
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, new FileOutputStream(file));
        Log.d(TAG, "getUri: path " + file.getAbsolutePath());
        return Uri.parse(file.getAbsolutePath());
    }
private Bitmap rotateImage(Bitmap img, int degree)
    {
        Matrix matrix = new Matrix();
        matrix.postRotate(degree);
        return Bitmap.createBitmap(img, 0, 0, img.getWidth(), img.getHeight(), matrix, false);
    }
public void updateTransform(int rotation, Size newBufferDimens, Size newViewFinderDimens) {
        if (rotation == viewFinderRotation &&
                newBufferDimens == bufferDimens &&
                newViewFinderDimens == viewFinderDimens) {
            // Nothing has changed, no need to transform output again
            //Log.d("AK", "nothing has changed, no need to transform output again");
            return;
        }

        if (newBufferDimens.getWidth() == 0 || newBufferDimens.getHeight() == 0) {
            // Invalid buffer dimens - wait for valid inputs before setting matrix
            //Log.d("AK", "returning from here newbufferdimens");
            return;
        } else {
            // Update internal field with new inputs
            bufferDimens = newBufferDimens;
        }

        if (newViewFinderDimens.getWidth() == 0 || newViewFinderDimens.getHeight() == 0) {
            // Invalid view finder dimens - wait for valid inputs before setting matrix
            //Log.d("AK", "returning from here newViewfinder");
            return;
        } else {
            // Update internal field with new inputs
            viewFinderDimens = newViewFinderDimens;
        }

        Matrix matrix = new Matrix();
        Log.d(TAG, "Applying output transformation.\n" +
                "View finder size: " + viewFinderDimens + "\n" +
                "Preview output size: " + bufferDimens + "\n" +
                "View finder rotation: " + viewFinderRotation + "\n" +
                "Preview output rotation: " + 0);
        float centerX = previewView.getWidth() / 2f;
        float centerY = previewView.getHeight() / 2f;

        // Correct preview output to account for display rotation
        float rotationDegrees;
        switch (previewView.getDisplay().getRotation()) {
            case Surface.ROTATION_0:
                rotationDegrees = 0f;
                break;
            case Surface.ROTATION_90:
                rotationDegrees = 90f;
                break;
            case Surface.ROTATION_180:
                rotationDegrees = 180f;
                break;
            case Surface.ROTATION_270:
                rotationDegrees = 270f;
                break;
            default:
                return;
        }
        matrix.postRotate(-rotationDegrees, centerX, centerY);

        float bufferRatio = bufferDimens.getHeight() / (float) bufferDimens.getWidth();
        int scaledWidth;
        int scaledHeight;

        if (previewView.getWidth() > previewView.getHeight()) {
            scaledHeight = viewFinderDimens.getWidth();
            scaledWidth = round(viewFinderDimens.getWidth() * bufferRatio);
        } else {
            scaledHeight = viewFinderDimens.getHeight();
            scaledWidth = round(viewFinderDimens.getHeight() * bufferRatio);
        }

        Canvas canvas = new Canvas();
        float xScale = scaledWidth / (float) viewFinderDimens.getWidth();
        float yScale = scaledHeight / (float) viewFinderDimens.getHeight();
        //Log.d("AK", "scale x y" + xScale + " " + yScale);
        matrix.preScale(xScale, yScale, centerX, centerY);

    }
private Bitmap imageProxytoBitmap(ImageProxy image) {

        ByteBuffer buffer =image.getPlanes()[0].getBuffer();
        buffer.rewind();
        byte[] bytes = new byte[buffer.capacity()];
        buffer.get(bytes);
        byte[] cloneBytes = bytes.clone();

        return BitmapFactory.decodeByteArray(cloneBytes, 0, cloneBytes.length);

    }

我希望捕获的图像与预览完全相同(未旋转的图像)

rxztt3cl

rxztt3cl1#

如果你在谷歌照片应用程序中打开旋转后的图像,它们还在旋转吗?如果不是,那么这意味着你没有使用EXIF信息。
基本上,当一张照片被捕获时,它可能会旋转,也可能不会旋转,这取决于OEM。当它没有旋转时,CameraX会将旋转信息保存在TAG_ORIENTATION标签中。您需要读取该信息并自己将其应用到位图上。类似于:

// Read the exif rotation value from the JPEG byte buffer
ExifInterface exifInterface = new ExifInterface(jpegFilePath);
int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED);

// Decode the JPEG byte buffer into a bitmap
Bitmap bitmap = BitmapFactory.decodeFile(jpegFilePath);

// Rotate the bitmap based on the exif rotation value
Matrix matrix = new Matrix();
switch (orientation) {
    case ExifInterface.ORIENTATION_ROTATE_90:
        matrix.postRotate(90);
        break;
    case ExifInterface.ORIENTATION_ROTATE_180:
        matrix.postRotate(180);
        break;
    case ExifInterface.ORIENTATION_ROTATE_270:
        matrix.postRotate(270);
        break;
}
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);

未测试代码。在旋转过程中可能需要交换宽度/高度。

相关问题