7

How to decrease the frame rate to 1 fps in image analysis so that I don't detect barcode multiple times. In my use-case, scanning the same barcode multiple times with a 1-second interval should increment a counter. So I want it to work correctly. (Similar to product scanner at shop tills)

cameraX version : 1.0.0-beta02

Similar questions :

Current implementation :

https://proandroiddev.com/update-android-camerax-4a44c3e4cdcc
Following this doc, to throttle image analysis.

override fun analyze(image: ImageProxy) {
    val currentTimestamp = System.currentTimeMillis()
    if (currentTimestamp - lastAnalyzedTimestamp >= TimeUnit.SECONDS.toMillis(1)) {
        // Image analysis code
    }
    image.close()
}

A better solution would be helpful.

Abhimanyu
  • 11,351
  • 7
  • 51
  • 121
  • Maybe it makes more sense to use an [Image Capture](https://developer.android.com/training/camerax/take-photo) use case in which you are in control of when the image is taken? I'm wondering the same for my project under a similar need atm. – topher217 Apr 02 '21 at 06:01
  • Just wanted to update and say that I tried it, and found that the imageProxy returned by the Image Capture use case is JPEG rather than YUV_420_888 that you get from Image Analysis. Maybe this is a good thing for some, but I didn't find any documentation as to the structure of the planes or buffer in this Android JPEG format, so I didn't know how to handle things from there so switching back to Image Analysis and just ignoring new images. – topher217 Apr 02 '21 at 07:22

3 Answers3

5

Tried bmdelacruz's solution. Had issues with closing the image.
Was getting an error similar to this.
Couldn't get it working.

Using delay worked well for me.

Code

CoroutineScope(Dispatchers.IO).launch {
    delay(1000 - (System.currentTimeMillis() - currentTimestamp))
    imageProxy.close()
}

Complete BarcodeAnalyser code

class BarcodeAnalyser(
    private val onBarcodesDetected: (barcodes: List<Barcode>) -> Unit,
) : ImageAnalysis.Analyzer {
    private val barcodeScannerOptions = BarcodeScannerOptions.Builder()
        .setBarcodeFormats(Barcode.FORMAT_ALL_FORMATS)
        .build()
    private val barcodeScanner = BarcodeScanning.getClient(barcodeScannerOptions)
    var currentTimestamp: Long = 0

    override fun analyze(
        imageProxy: ImageProxy,
    ) {
        currentTimestamp = System.currentTimeMillis()
        imageProxy.image?.let { imageToAnalyze ->
            val imageToProcess =
                InputImage.fromMediaImage(imageToAnalyze, imageProxy.imageInfo.rotationDegrees)
            barcodeScanner.process(imageToProcess)
                .addOnSuccessListener { barcodes ->
                    // Success handling
                }
                .addOnFailureListener { exception ->
                    // Failure handling
                }
                .addOnCompleteListener {
                    CoroutineScope(Dispatchers.IO).launch {
                        delay(1000 - (System.currentTimeMillis() - currentTimestamp))
                        imageProxy.close()
                    }
                }
        }
    }
}
Abhimanyu
  • 11,351
  • 7
  • 51
  • 121
2

You can take advantage of the fact that the next analysis will not begin until you close the provided ImageProxy.

In my case, I just put the thread to sleep since my analyzer's executor is a single thread executor.

class MyAnalyzer : ImageAnalysis.Analyzer {
    override fun analyze(image: ImageProxy) {
        val elapsedAnalysisTime = measureTimeMillis {
            // do your stuff here
        }
        image.use {
            if (elapsedAnalysisTime < 1000) {
                Thread.sleep(1000 - elapsedAnalysisTime)
            }
        }
    }
}
bmdelacruz
  • 2,366
  • 1
  • 19
  • 26
-2

private var firstDetected = true

for (barcode in barcodes) {
            if (barcodes.size > 0 && firstDetected) {
                LoggingUtility.writeLog("Analyzer",
                        "MLKitBarcode Result",
                        "Barcode is ${barcode.rawValue!!}")
                firstDetected = false
       }
}

This might help

Utsav Dave
  • 85
  • 1
  • 3
  • 9