13

I'm investigating the new CameraX API, in relation to how viable it might be to switch over from our current Camera2 system.

In our Camera2 system, we use an OpenGL surface to capture the frames from a PreviewCaptureSession, and we are hitting consistent 30fps image processing speeds across most devices, with some able to hit 60fps with AutoExposure settings enabled.

CameraX isn't giving anything near that speed and I'm not sure if its something I've missed in setup.

I've setup the test examples for CameraX and ImageAnalysis, but I'm getting locked frame rates for the number of images that comes through.

For example, I could set the resolution as low as 320x240 up to 1920x960 and both will come out at a (seemingly capped) 16fps.

When I add a Preview usecase to run along side it, and set enableTorch(true), the ImageAnalysis usecase will suddenly start getting more like 20fps, with it occasionally peaking up to 30ish.

Clearly the Preview usecase alters some of the AutoExposure state of the camera?

Here's a snippet of my current setup...

 private fun startCameraAnalysis() {
        val metrics = DisplayMetrics().also { viewFinder.display.getRealMetrics(it) }
        var resolution = Size(metrics.widthPixels, metrics.heightPixels)
        resolution = Size(640, 480) //set to fixed size for testing

        val aspectRatio = Rational(resolution.width, resolution.height)
        val rotation = viewFinder.display.rotation

        // Setup image analysis pipeline
        val analyzerConfig = ImageAnalysisConfig.Builder().apply {
            val analyzerThread = HandlerThread(
                "LuminosityAnalysis").apply { start() }
            setCallbackHandler(Handler(analyzerThread.looper))
     setImageReaderMode(ImageAnalysis.ImageReaderMode.ACQUIRE_LATEST_IMAGE)
            setTargetRotation(rotation)
            setTargetAspectRatio(aspectRatio)
            setTargetResolution(resolution)
        }.build()

        // Setup preview pipeline
        val previewConfig = PreviewConfig.Builder().apply {
            setTargetRotation(rotation)
            setTargetAspectRatio(aspectRatio)
            setTargetResolution(resolution)
        }.build()

        // Build Preview useCase
        val preview = Preview(previewConfig)
        preview.enableTorch(true)

        // Build Analysis useCase
        val analyzer = ImageAnalysis(analyzerConfig)
        analyzer.analyzer = LuminosityAnalyzer()

        CameraX.bindToLifecycle(this, preview, analyzer )
        preview.enableTorch(true)
}

Is there anyway to alter the camera settings in CameraX around the ImageAnalysis to get higher frame rates?

Is there anyway at all in fact to alter things like Sensor Duration, ISO, exposure?

Richard Onslow Roper
  • 5,477
  • 2
  • 11
  • 42
Iain Stanford
  • 606
  • 1
  • 6
  • 18

4 Answers4

11

So I've spent some more time investigating and I think I've come up with a solution for now.

It turns out, the ImageAnalysisConfig is not extendable, so you can't alter the camera configuration when just using one of those, so the default camera settings will be used which on my phone I think resulted in AE being on and hitting 16ish FPS.

If you spin up a PreviewConfig to run along side it at the same time, you can then extend this with a Camera2Config.Extender and alter the camera2 properties directly. This can increase the camera preview frame rate, and the Analyser will also start getting frames at the same rate.

So for example, I add this to my PreviewConfig...

    // Create Camera2 extender
    var camera2Extender = Camera2Config.Extender(previewConfig)
        .setCaptureRequestOption(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_OFF)
        .setCaptureRequestOption(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_OFF)
        .setCaptureRequestOption(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_OFF)
        .setCaptureRequestOption(CaptureRequest.CONTROL_AWB_MODE, CaptureRequest.CONTROL_AWB_MODE_OFF)
        .setCaptureRequestOption(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH)
        .setCaptureRequestOption(CaptureRequest.SENSOR_SENSITIVITY, 100)
        .setCaptureRequestOption(CaptureRequest.SENSOR_FRAME_DURATION, 16666666)
        .setCaptureRequestOption(CaptureRequest.SENSOR_EXPOSURE_TIME, 20400000)

So this started hitting 30fps fine in the ImageAnalyser.

If I want to hit 60, I can set...

.setCaptureRequestOption(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_OFF)
.setCaptureRequestOption(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, Range(60,60))

Obviously assuming the device support (60,60) target FPS range.

So it seems the full Camera2 logic is still available in CameraX, its just a bit clunky that its a little hidden away in a Camera2Config extender, and this only works with Preview use cases.

Iain Stanford
  • 606
  • 1
  • 6
  • 18
  • Where exactly am I to add this? I assume we'll need to pass the initialised camera2Extender object to some other function/constructor via invocation? – Richard Onslow Roper Sep 12 '22 at 06:08
  • Also, I assume this just enhances the frame rate on the preview surface, not the image-analysis case, because that would be directly dependent on the amount of processing we manually do in the analyze overridden method of the analyser. How could you say it starts reflecting the framerate you set here? – Richard Onslow Roper Sep 12 '22 at 06:16
  • Also, I can't see the `Extender` companion in the latest releases; `1.1.0-beta01` is what I am using, which is not the latest but is close enough. – Richard Onslow Roper Sep 12 '22 at 10:23
9

Alright, this was driving me crazy for hours.

Expanding upon Ian's answer for the newest version of CameraX, you can now extend ImageAnalysis directly. See CameraX equivalent of Camera2's CaptureRequest

So to get 60FPS, we can use this modified code (example in Java and Kotlin):

// Java

ImageAnalysis.Builder builder = new ImageAnalysis.Builder();
Camera2Interop.Extender ext = new Camera2Interop.Extender<>(builder);
ext.setCaptureRequestOption(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_OFF);
ext.setCaptureRequestOption(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, new Range<Integer>(60, 60));
ImageAnalysis imageAnalysis = builder.build();

// Kotlin

val builder = ImageAnalysis.Builder()
val ext: Camera2Interop.Extender<*> = Camera2Interop.Extender(builder)
ext.setCaptureRequestOption(
                CaptureRequest.CONTROL_AE_MODE,
                CaptureRequest.CONTROL_AE_MODE_OFF
            )
ext.setCaptureRequestOption(
                CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE,
                Range<Int>(60, 60)
            )
val imageAnalysis = builder.build()
JaydeepW
  • 3,237
  • 1
  • 25
  • 27
Miramur
  • 91
  • 1
  • 2
  • 3
    Tried this in a Samsung Galaxy S8 selfie camera and didn't work, as soon as I add these parameters the preview turns black and the analysis doesn't seem to be actually getting frames any more, even if I allow a lower range (say 10 to 60 instead of 60 to 60) – Fran Marzoa Sep 23 '21 at 11:04
  • I have tried this on OnePlus 7T Maclaren, the preview turns dark, slightly visible. – PalFS Jan 25 '23 at 12:09
  • After removing "CaptureRequest.CONTROL_AE_MODE", the preview is visible but blinking maybe due to high FPS range set. – PalFS Jan 25 '23 at 12:18
  • Frames turning dark may be due to basic rules of photography. High frame rate means low exposure time. If there is a way to increase sensitivity of the CMOS (ISO) that could help – Fakeer May 14 '23 at 15:52
5

Unfortunately, Iain Stanford answer did not help me. My app just crash after adding any of these lines to Camera2Config.Extender:

.setCaptureRequestOption(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_OFF)
.setCaptureRequestOption(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_OFF)
.setCaptureRequestOption(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_OFF)
.setCaptureRequestOption(CaptureRequest.CONTROL_AWB_MODE, CaptureRequest.CONTROL_AWB_MODE_OFF)

I got this error:

IllegalArgumentException: Unsupported session configuration combination

But, luckily, I found a way to get 60 FPS another way on Pixel 2 XL. Took some code from here. Unfortunately, it works only if I draw Preview as TextureView. If I use don't use AutoFitPreviewBuilder function and don't draw Preview as TextureView, all Extender settings will be ignored.

So, my code:

imageAnalysis = ImageAnalysis(createImageAnalysisConfig())

val previewConfig  = createImagePreviewConfig()
Camera2Config.Extender(previewConfig)
    .setCaptureRequestOption(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, Range(60, 60))             
    .setCaptureRequestOption(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION, 1)

val preview = AutoFitPreviewBuilder.build(previewConfig.build(), viewFinder)

CameraX.bindToLifecycle(lifecycleOwner, imageAnalysis, preview)
preview.enableTorch(true)

Where AutoFitPreviewBuilder is function from android repo examples and viewFinder is TextureView, imageAnalysis is ImageAnalysisConfig.Builder().build and createImagePreviewConfig() returns PreviewConfig.Builder(). Btw, do not forget to set max resolution for camera in ImageAnalysisConfig & PreviewConfig:

.setMaxResolution(Size(800, 800))

Hope, it will help you.

GTnik
  • 101
  • 5
-1

i had the same problem what i did is just added .setTargetResolution(Size(1280, 720)) this line in :- val imageAnalyzer = ImageAnalysis.Builder().setTargetResolution(Size(1280, 720)) .build() .also { it.setAnalyzer(cameraExecutor, LuminosityAnalyzer { luma> Log.d(TAG, "Average luminosity: $luma") }) } reference:- https://developer.android.com/training/camerax/configuration

  • Lowering resolution is not the best solution. There's other ways with adjusting bitrate. – asozcan Aug 03 '21 at 10:59
  • that i know but answer was for fps drop not for the best solution,did you read my ans ?there is no lowering resolution in my answer – Versatile Pro Aug 04 '21 at 06:53