简体   繁体   English

Camera 2 API会在捕获后降低质量

[英]Camera 2 API reduces the quality after capture

I am using Camera in my app to take pictures of ID cards, I have a rectangular overlay to which image will be cropped. 我在我的应用程序中使用相机拍摄身份证的照片,我有一个矩形覆盖图像将被裁剪的图像。 issue is that the image quality is reduced once the image is captured. 问题是一旦捕获图像,图像质量会降低。

I am unable to figure out where exactly it is happening. 我无法弄清楚究竟发生了什么。 In cutImage method, I am cutting the image but I don't think I am doing anything to the resolution of the image there. 在cutImage方法中,我正在剪切图像,但我认为我没有对图像的分辨率做任何事情。

Can any one suggest where the quality might be going down. 任何人都可以建议质量可能下降的地方。

takePicture is called when the user clicks to take the picture. 当用户点击拍照时调用takePicture。 Once the picture is taken there is a button 'use picture' that is when usePicture is called. 拍摄照片后,会出现一个按钮“使用图片”,即调用usePicture时。

cutImage method is used to crop the image based on the preview. cutImage方法用于根据预览裁剪图像。

any suggestions on how to stop the resolution from going down will be very very helpful 任何关于如何阻止决议下降的建议将非常有帮助

protected void takePicture() {
    Log.e(TAG, "takePicture started");
    if(null == cameraDevice) {
        Log.e(TAG, "cameraDevice is null");
        return;
    }
    try {
        ImageReader reader = ImageReader.newInstance(textureViewWidth, textureViewHeight, ImageFormat.JPEG, 1);
        List<Surface> outputSurfaces = new ArrayList<Surface>(2);
        outputSurfaces.add(reader.getSurface());
        outputSurfaces.add(new Surface(textureView.getSurfaceTexture()));
        final CaptureRequest.Builder captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
        captureBuilder.addTarget(reader.getSurface());
        captureBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
        // Orientation
        int rotation = getActivity().getWindowManager().getDefaultDisplay().getRotation();
        captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));
        ImageReader.OnImageAvailableListener readerListener = new ImageReader.OnImageAvailableListener() {
            @Override
            public void onImageAvailable(ImageReader reader) {
                Image image = null;
                try {
                    image = reader.acquireLatestImage();
                    ByteBuffer buffer = image.getPlanes()[0].getBuffer();
                    byte[] bytes = new byte[buffer.capacity()];
                    buffer.get(bytes);
                    takenPictureBytes = bytes;
                    Log.d(TAG, "takenPictureBytes length - " + takenPictureBytes.length);

                } catch (Exception e) {
                    Log.d(TAG, " onImageAvailable exception ");
                    e.printStackTrace();
                } finally {
                    if (image != null) {
                        Log.d(TAG, " image closing");
                        image.close();
                    }
                }
            }
        };
        reader.setOnImageAvailableListener(readerListener, mBackgroundHandler);
        final CameraCaptureSession.CaptureCallback captureListener = new CameraCaptureSession.CaptureCallback() {
            @Override
            public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
                super.onCaptureCompleted(session, request, result);
                Log.d(TAG, "takePicture - camera capture session");
                switchPanels(true);
                progress.setVisibility(View.GONE);
            }
        };
        cameraDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback() {
            @Override
            public void onConfigured(CameraCaptureSession session) {
                try {
                    session.capture(captureBuilder.build(), captureListener, mBackgroundHandler);
                } catch (CameraAccessException e) {
                    Log.d(TAG, "takePicture - onConfigured- camera access exception ");
                    e.printStackTrace();
                }
            }
            @Override
            public void onConfigureFailed(CameraCaptureSession session) {
                Log.d(TAG, "takePicture - onConfigureFailed");

            }
        }, mBackgroundHandler);
    } catch (CameraAccessException e) {
        Log.d(TAG, "takePicture - CameraAccessException ");
        e.printStackTrace();
    }
}

private void usePicture() {
    Log.d(TAG, "usePicture - started     ");

    if(null != takenPictureBytes ){
        try{
            String imagePath = null;

            Bitmap bitmap = BitmapFactory.decodeByteArray(takenPictureBytes, 0, takenPictureBytes.length);
            int bitmapByteCountUsePic = byteSizeOf(bitmap);
            Matrix matrix = new Matrix();
            matrix.postRotate(90);
            Bitmap rotatedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);

            if (isFrameMode) {
                float withRatio = (float) rotatedBitmap.getWidth() / (float) textureViewWidth;
                float heightRatio = (float) rotatedBitmap.getHeight() / (float) textureViewHeight;

                Bitmap newImage = cutImage(rotatedBitmap, (int) (photoFrameView.getWidth() * withRatio), (int) (photoFrameView.getHeight() * heightRatio), withRatio);
                int bitmapByteCountNewImage = byteSizeOf(newImage);
                imagePath = saveBitmap(newImage);
            } else {
                imagePath = saveBitmap(rotatedBitmap);
            }
            TakePhotoFragment.TakePhotoFragmentEvent takePhotoFragmentEvent = new TakePhotoFragment.TakePhotoFragmentEvent();
            takePhotoFragmentEvent.setImagePath(imagePath);
            // send rxjava
            //pop backstack
            RxBus.getInstance().post(takePhotoFragmentEvent);
            getActivity().getSupportFragmentManager().popBackStack();
        }catch (Exception e){
            Log.d(TAG, "usePicture - exception     ");
            e.printStackTrace();
        }
    }else{
        Log.d(TAG, "usePicture - takenPictureBytes is null");
        DialogUtil.showErrorSnackBar(getView(), R.string.retake_photo );
    }
}

public Bitmap cutImage(final Bitmap bitmap, final int pixepWidth, final int pixelsHeight, float widthRatio) {
    int bitmapByteCountCutImage = byteSizeOf(bitmap);
    Bitmap output = createBitmap(pixepWidth, pixelsHeight, Bitmap.Config.ARGB_8888);
    Bitmap original = bitmap;

    final Paint paint = new Paint();
    Canvas canvas = new Canvas(output);
    int padding = (int) ((float) getResources().getDimensionPixelSize(R.dimen.double_padding) * widthRatio);

    Rect rect = new Rect(padding, (original.getHeight() - pixelsHeight) / 2, padding + pixepWidth, original.getHeight() - (original.getHeight() - pixelsHeight) / 2);

    final RectF cutedRect = new RectF(0, 0, pixepWidth, pixelsHeight);
    paint.setAntiAlias(true);
    canvas.drawARGB(0, 0, 0, 0);
    canvas.drawBitmap(original, rect, cutedRect, paint);
    return output;
}

   private String saveBitmap(Bitmap bitmap) {
    File pictureFileDir = getDir();

    if (!pictureFileDir.exists() && !pictureFileDir.mkdirs()) {
        Toast.makeText(getActivity(), "Can't create directory to save image.", Toast.LENGTH_LONG).show();
        return null;

    }

    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyymmddhhmmssSSS");
    String date = dateFormat.format(new Date());
    String photoFile = "Picture_" + date + ".jpg";

    String filename = pictureFileDir.getPath() + File.separator + photoFile;

    File pictureFile = new File(filename);

    try {
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);

        FileOutputStream fos = new FileOutputStream(pictureFile);
        fos.write(stream.toByteArray());
        fos.close();

        return pictureFile.getAbsolutePath();

    } catch (Exception error) {
        Log.d(TAG, "File" + filename + "not saved: " + error.getMessage());
    }

    return null;
}

You are changing the bitmap size/resolution in this code: 您正在更改此代码中的位图大小/分辨率:

            float withRatio = (float) rotatedBitmap.getWidth() / (float) textureViewWidth;
        float heightRatio = (float) rotatedBitmap.getHeight() / (float) textureViewHeight;

        Bitmap newImage = cutImage(rotatedBitmap, (int) (photoFrameView.getWidth() * withRatio), (int) (photoFrameView.getHeight() * heightRatio), withRatio);
        int bitmapByteCountNewImage = byteSizeOf(newImage);
        imagePath = saveBitmap(newImage);

Put in a breakpoint and see what the new heightRatio and widthRatio are, and what the photoFrameView.getWidth() * withRatio value comes out to. 放入一个断点,看看新的heightRatio和widthRatio是什么,以及photoFrameView.getWidth()* withRatio值是什么。 I think you will find it is small compared to the original image. 我想你会发现它与原始图像相比很小。 I'm not sure why you are calculating the Ratios with the textureViewWidth/Height, you shouldn't have to do that. 我不确定你为什么用textureViewWidth / Height来计算比率,你不应该这样做。 Whatever you are displaying the image in should be able to 'Fill' without having to change the size of the underlying bitmap, and thus losing resolution. 无论你在显示什么图像,都应该能够“填充”,而不必改变底层位图的大小,从而失去分辨率。

You might check out this method: 您可以查看此方法:

rawBitmap = ((BitmapDrawable)imageToLoad.getDrawable()).getBitmap();
theBitmap = Bitmap.createScaledBitmap(rawBitmap, 285, 313, false);

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

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