简体   繁体   English

为什么CameraX图像在Android手机Redmi 9T中保存时会失真?

[英]Why CameraX image distorted when saved in Android phone Redmi 9T?

I am using the new device Redmi 9T.我正在使用新设备 Redmi 9T。 Following the basic setup from this post , i manage to up and run an app using CameraX.按照这篇文章的基本设置,我设法使用 CameraX 启动并运行应用程序。 Everything works fine until i want to save the frame to the local, in the setAnalyzer function一切正常,直到我想将框架保存到本地,在setAnalyzer

private void bindImageAnalysis(@NonNull ProcessCameraProvider cameraProvider) {
    ImageAnalysis imageAnalysis =
            new ImageAnalysis.Builder().setTargetResolution(new Size(720, 1280))
                    .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST).build();

    imageAnalysis.setAnalyzer(ContextCompat.getMainExecutor(this), new ImageAnalysis.Analyzer() {
        @Override
        public void analyze(@NonNull ImageProxy imageProxy) {
            @SuppressLint("UnsafeExperimentalUsageError") Image image = imageProxy.getImage();
            Bitmap finalBitmap = getFinalScaledRotatedBitmap(image,270); //rotate it properly (portrait)
            saveBitmap(finalBitmap, "test"); //save with a dummy name
            imageProxy.close();
        }
    });
    OrientationEventListener orientationEventListener = new OrientationEventListener(this) {
        @Override
        public void onOrientationChanged(int orientation) {
            textView.setText(Integer.toString(orientation));
        }
    };
    orientationEventListener.enable();
    Preview preview = new Preview.Builder().build();
    CameraSelector cameraSelector = new CameraSelector.Builder()
            .requireLensFacing(CameraSelector.LENS_FACING_FRONT).build();
    preview.setSurfaceProvider(previewView.createSurfaceProvider());
    cameraProvider.bindToLifecycle((LifecycleOwner)this, cameraSelector,
            imageAnalysis, preview);
}

 /*
 *  Rotate the image with a rotation degree
 */
 private Bitmap getFinalScaledRotatedBitmap(Image imageData, int viewRotation){
    Bitmap originalBitmap = toBitmap(imageData);
    Matrix matrix = new Matrix();
    matrix.postRotate(viewRotation);
    matrix.postScale(-1.0f, 1.0f);
    Bitmap scaledBitmap = Bitmap.createScaledBitmap(originalBitmap, originalBitmap.getWidth(), originalBitmap.getHeight(), true);
    Bitmap finalRotatedBitmap = Bitmap.createBitmap(scaledBitmap, 0, 0, scaledBitmap.getWidth(), scaledBitmap.getHeight(), matrix, true);
    return finalRotatedBitmap;
}

/*
*  Convert Image format to Bitmap
*/
private Bitmap toBitmap(Image image) {
    Image.Plane[] planes = image.getPlanes();
    ByteBuffer yBuffer = planes[0].getBuffer();
    ByteBuffer uBuffer = planes[1].getBuffer();
    ByteBuffer vBuffer = planes[2].getBuffer();

    int ySize = yBuffer.remaining();
    int uSize = uBuffer.remaining();
    int vSize = vBuffer.remaining();

    byte[] nv21 = new byte[ySize + uSize + vSize];
    //U and V are swapped
    yBuffer.get(nv21, 0, ySize);
    vBuffer.get(nv21, ySize, vSize);
    uBuffer.get(nv21, ySize + vSize, uSize);

    YuvImage yuvImage = new YuvImage(nv21, ImageFormat.NV21, image.getWidth(), image.getHeight(), null);
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    yuvImage.compressToJpeg(new Rect(0, 0, yuvImage.getWidth(), yuvImage.getHeight()), 100, out);

    byte[] imageBytes = out.toByteArray();
    return BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length);
}

/*
*  Save Bitmap to local
*/
public void saveBitmap(Bitmap bitmap, String personName) {
    String ROOT =
            Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "cameraX";

    File myDir = new File(ROOT + File.separator + personName);
    if (!myDir.mkdirs()) {
        Log.e("FileUtil", "save dir fails");
    }

    String fileName = (new SimpleDateFormat("yyyyMMdd_HHmmss_SSS")).format(Calendar.getInstance().getTime()) + ".jpeg";
    File file = new File(myDir, fileName);
    if (file.exists()) {
        file.delete();
    }

    try {
        FileOutputStream out = new FileOutputStream(file);
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);

        out.flush();
        out.close();
    } catch (Exception var6) {
        Log.e("fileUtil", var6.getMessage());
    }

}

Output? Output? (regardless of Lens front or back) (无论镜头正面还是背面)

扭曲的图像

The thing is, it works fine in other device like honor 8x, or realme.问题是,它在其他设备(如 Honor 8x 或 realme)中运行良好。 So, what could possibly go wrong?那么,go 可能有什么问题呢?

The issue might be with your conversion method toBitmpa() , it assumes the image's format is NV21, but unfortunately not every YUV_888_420 buffer is NV21 format.问题可能出在您的转换方法toBitmpa()上,它假定图像的格式是 NV21,但不幸的是,并非每个 YUV_888_420 缓冲区都是 NV21 格式。 it can also be NV12, YU12 or YV12 format.它也可以是 NV12、YU12 或 YV12 格式。

The official CameraX documentation already provides a way to convert YUV images to RGB bitmaps which you should use, it's at the bottom of this section from the documentation. CameraX 官方文档已经提供了一种将 YUV 图像转换为您应该使用的 RGB 位图的方法,它位于文档本节的底部。

For sample code that shows how to convert a Media.Image object from YUV_420_888 format to an RGB Bitmap object, see YuvToRgbConverter.kt .有关显示如何将 Media.Image object 从 YUV_420_888 格式转换为 RGB Bitmap object 的示例代码,请参阅YuvToRgbConverter

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM