c0nst
c0nst

Reputation: 755

CameraX | Enable/Disable image analysis

I'm trying to implement barcode scanner using CameraX and ZXing barcode scanning library.

I've wrote a custom Analyzer that decodes barcodes and those barcodes should be processed (processing logic obviously takes some time).

So what I want is to disable image analysis on the fly and enable it again if the result of the processing operation wasn't successful.

My base setup logic:

    private fun setupCamera() {
        processCameraProvider.unbindAll()
        val camera = processCameraProvider.bindToLifecycle(
            this,
            CameraSelector.DEFAULT_BACK_CAMERA,
            buildPreviewUseCase(),
            buildImageAnalysisUseCase())
    }

    private fun buildPreviewUseCase(): Preview {
        return Preview.Builder()
            .setTargetRotation(cameraPreview.display.rotation)
            .build()
            .apply {
                previewSurfaceProvider = cameraPreview.previewSurfaceProvider
            }
    }

    private fun buildImageAnalysisUseCase(): ImageAnalysis {
        return ImageAnalysis.Builder()
            .setTargetRotation(cameraPreview.display.rotation)
            .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
            .build()
            .apply {
                setAnalyzer(Executors.newSingleThreadExecutor(),
                    ZxingBarcodeAnalyzer { qrResult ->
                        Handler(Looper.getMainLooper()).post {
                            viewModel.handleBarcode(qrResult.text)
                        }
                    })
            }
    }

After digging around the library sources I'm still don’t understand how I can achieve desired behaviour?

If I call unbind(imageAnalysisUseCase object) on the processCameraProvider I can't bind that object again (processCameraProvider has only bindToLifecycle() method, not bind(imageAnalysisUseCase object)).

Calling clearAnalyzer() on the ImageAnalysis resets image analysis completely despite calling setAnalyzer() again.

Upvotes: 6

Views: 5491

Answers (3)

Emmanuel Osimosu
Emmanuel Osimosu

Reputation: 6004

You can ask the producer to produce one image at a time, until you close the proxy.

ImageAnalysis imageAnalysis = imageAnalysisBuilder.setBackpressureStrategy(ImageAnalysis.STRATEGY_BLOCK_PRODUCER).setImageQueueDepth(1).build();

From the docs, https://developer.android.com/reference/androidx/camera/core/ImageAnalysis#STRATEGY_BLOCK_PRODUCER

Block the producer from generating new images.

Once the producer has produced the number of images equal to the image queue depth, and none have been closed, the producer will stop producing images. Note that images may be queued internally and not be delivered to the analyzer until the last delivered image has been closed with ImageProxy.close()

Upvotes: 2

Husayn Hakeem
Husayn Hakeem

Reputation: 4570

If all you want to do is not process any images while an image is being processed, you can set a tag inside the analysis method that returns immediately if an image is being processed. Something like this:

class MyViewModel: ViewModel() {

    private var isProcessing = false

    fun handleBarcode(text: String) {
        if (isProcessing) {
            return
        }
        // Do your processing here.
    }
}

If you call processCameraProvider.unbind(imageAnalysis), you can bind the use case again by calling processCameraProvider.bindToLifecycle(, , imageAnalysis) using the same instance, but I'm not sure if this would work. Re-binding the same Preview use case instance doesn't work, I'm not sure if the rule applies to ImageAnalysis.

Upvotes: 1

Sz-Nika Janos
Sz-Nika Janos

Reputation: 821

there is a issue with the clearAnalyzer()

I'm using like this until is fix :

  fun enableAnalysis(enable: Boolean) {
    if (!enable) {
        isAnalyzerSet = false
        imageAnalysisUseCase?.clearAnalyzer()
        imageAnalysisUseCase.setAnalyzer(analysisExecutor, ImageAnalysis.Analyzer { })

    } else {
        if (isAnalyzerSet) return
        isAnalyzerSet = true
        imageAnalysisUseCase?.setAnalyzer(analysisExecutor, analyzer)
    }
}

Upvotes: 1

Related Questions