简体   繁体   English

如何使用 CameraX 提高 Android 中的相机速度

[英]How to increase Camera Speed in Android with CameraX

Hi I am new to Android Programming.嗨,我是 Android 编程的新手。

As the title, How to increase speed of take picture with CameraX or Camera2 or OpenCV?如标题,如何提高 CameraX 或 Camera2 或 OpenCV 的拍照速度? My project goal is image processing(4k image) with Android and OpenCV as fast as possible.我的项目目标是尽可能快地使用 Android 和 OpenCV 进行图像处理(4k 图像)。

If you have any comments, please let me know.如果您有任何意见,请告诉我。

void bindPreview(@NonNull ProcessCameraProvider cameraProvider) {

        Preview preview = new Preview.Builder()
                .setTargetAspectRatio(AspectRatio.RATIO_16_9)
                .build();

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

        executor = Executors.newSingleThreadExecutor();

        ImageAnalysis imageAnalysis = new ImageAnalysis.Builder()
                .setTargetAspectRatio(AspectRatio.RATIO_16_9)
                .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
                .build();

        ImageCapture imageCapture = new ImageCapture.Builder()
                .setTargetAspectRatio(AspectRatio.RATIO_16_9)
                .setCaptureMode(ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY)
                .build();

        camera_capture_button.setOnClickListener(new View.OnClickListener(){

            @Override
            public void onClick(View v){
                Log.v("Info", "Button Click");
                imageCapture.takePicture(executor , new ImageCapture.OnImageCapturedCallback() {
                    @Override
                    public void onCaptureSuccess(@NonNull ImageProxy image) {
                        super.onCaptureSuccess(image);
                        Log.v("Info", "Capture Success = W:" + image.getWidth() + "/" + "H:" + image.getHeight());

                        Bitmap bitmap = toBitmap(image);
                        Log.v("Info", "Bitmat cvt = W:" + bitmap.getWidth() + "/" + "H:" + bitmap.getHeight());

                        Mat matOriginal = new Mat();
                        Mat matResult = new Mat();
                        Utils.bitmapToMat(bitmap, matOriginal);
                        Log.v("Info", "Mat cvt = W:" + matOriginal.width() + "/" + "H:" + matOriginal.height());

                        Imgproc.cvtColor(matOriginal, matResult, Imgproc.COLOR_BGR2HSV);

                        image.close();
                    }

                    @Override
                    public void onError(@NonNull ImageCaptureException exception) {
                        Log.v("Info", "Capture Error");
                        exception.printStackTrace();
                    }
                });
            }
        });

Here is Logcat Message to measure Time这是用于测量时间的 Logcat 消息

2021-05-12 16:20:40.427 V/Info: Button Click 2021-05-12 16:20:40.427 V/Info: 按钮点击

2021-05-12 16:20:40.976 V/Info: Capture Success = W:3840/H:2160 2021-05-12 16:20:40.976 V/信息:捕获成功 = W:3840/H:2160

2021-05-12 16:20:41.092 V/Info: Bitmap cvt = W:3840/H:2160 2021-05-12 16:20:41.092 V/信息:Bitmap cvt = W:3840/H:2160

2021-05-12 16:20:41.106 V/Info: Mat cvt = W:3840/H:2160 2021-05-12 16:20:41.106 V/信息:Mat cvt = W:3840/H:2160

as the Result作为结果

549msec - takePicture (too Slow, I think) 549msec - takePicture(我觉得太慢了)

116msec - Bitmap Conversion 116 毫秒 - Bitmap 转换

014msec - Mat Conversion 014msec - 垫转换

if you don't want resolution image is high.如果您不希望分辨率图像很高。 you can use image analysis for high speed capture https://developer.android.com/training/camerax/analyze您可以使用图像分析进行高速捕获https://developer.android.com/training/camerax/analyze

You can try to convert the image to Mat without converting first to bitmap, Use this extension function:您可以尝试将图像转换为 Mat 而无需先转换为 bitmap,使用此扩展名 function:

fun Image.yuvToRgba(): Mat {
  val rgbaMat = Mat()

  if (format == ImageFormat.YUV_420_888
    && planes.size == 3) {

    val chromaPixelStride = planes[1].pixelStride

    if (chromaPixelStride == 2) { // Chroma channels are interleaved
        assert(planes[0].pixelStride == 1)
        assert(planes[2].pixelStride == 2)
        val yPlane = planes[0].buffer
        val uvPlane1 = planes[1].buffer
        val uvPlane2 = planes[2].buffer
        val yMat = Mat(height, width, CvType.CV_8UC1, yPlane)
        val uvMat1 = Mat(height / 2, width / 2, CvType.CV_8UC2, uvPlane1)
        val uvMat2 = Mat(height / 2, width / 2, CvType.CV_8UC2, uvPlane2)
        val addrDiff = uvMat2.dataAddr() - uvMat1.dataAddr()
        if (addrDiff > 0) {
            assert(addrDiff == 1L)
            Imgproc.cvtColorTwoPlane(yMat, uvMat1, rgbaMat, Imgproc.COLOR_YUV2BGR_NV12)
        } else {
            assert(addrDiff == -1L)
            Imgproc.cvtColorTwoPlane(yMat, uvMat2, rgbaMat, Imgproc.COLOR_YUV2BGR_NV21)
        }
    } else { // Chroma channels are not interleaved
        val yuvBytes = ByteArray(width * (height + height / 2))
        val yPlane = planes[0].buffer
        val uPlane = planes[1].buffer
        val vPlane = planes[2].buffer

        yPlane.get(yuvBytes, 0, width * height)

        val chromaRowStride = planes[1].rowStride
        val chromaRowPadding = chromaRowStride - width / 2

        var offset = width * height
        if (chromaRowPadding == 0) {
            // When the row stride of the chroma channels equals their width, we can copy
            // the entire channels in one go
            uPlane.get(yuvBytes, offset, width * height / 4)
            offset += width * height / 4
            vPlane.get(yuvBytes, offset, width * height / 4)
        } else {
            // When not equal, we need to copy the channels row by row
            for (i in 0 until height / 2) {
                uPlane.get(yuvBytes, offset, width / 2)
                offset += width / 2
                if (i < height / 2 - 1) {
                    uPlane.position(uPlane.position() + chromaRowPadding)
                }
            }
            for (i in 0 until height / 2) {
                vPlane.get(yuvBytes, offset, width / 2)
                offset += width / 2
                if (i < height / 2 - 1) {
                    vPlane.position(vPlane.position() + chromaRowPadding)
                }
            }
        }

        val yuvMat = Mat(height + height / 2, width, CvType.CV_8UC1)
        yuvMat.put(0, 0, yuvBytes)
        Imgproc.cvtColor(yuvMat, rgbaMat, Imgproc.COLOR_YUV2BGR_I420, 4)
    }
}

return rgbaMat
}

And call it this way:并这样称呼它:

image.image?.let {
  if (it.format == ImageFormat.YUV_420_888
      && it.planes.size == 3
  ) {
      val rgbaMat = it.yuvToRgba()
  }
}

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

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