I’m trying to use MlKit to read barcodes in my Android application, I draw an overlay with a rectangle box in it’s middle, which should be the area where the barcode must be read.
Here is my overlay code:
class ViewFinderOverlay(context: Context, attrs: AttributeSet) : View(context, attrs) {
private val boxPaint: Paint = Paint().apply {
color = ContextCompat.getColor(context, R.color.barcode_reticle_stroke)
style = Paint.Style.STROKE
strokeWidth = context.resources.getDimensionPixelOffset(R.dimen.barcode_reticle_stroke_width).toFloat()
}
private val scrimPaint: Paint = Paint().apply {
color = ContextCompat.getColor(context, R.color.barcode_reticle_background)
}
private val eraserPaint: Paint = Paint().apply {
strokeWidth = boxPaint.strokeWidth
xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR)
}
private val boxCornerRadius: Float =
context.resources.getDimensionPixelOffset(R.dimen.barcode_reticle_corner_radius).toFloat()
private var boxRect: RectF? = null
fun setViewFinder() {
val overlayWidth = width.toFloat()
val overlayHeight = height.toFloat()
val boxWidth = overlayWidth * 80 / 100
val boxHeight = overlayHeight * 36 / 100
val cx = overlayWidth / 2
val cy = overlayHeight / 2
boxRect = RectF(cx - boxWidth / 2, cy - boxHeight / 2, cx + boxWidth / 2, cy + boxHeight / 2)
invalidate()
}
fun getViewFinder(): Rect {
val overlayWidth = width.toFloat()
val overlayHeight = height.toFloat()
val boxWidth = overlayWidth * 80 / 100
val boxHeight = overlayHeight * 36 / 100
val cx = overlayWidth / 2
val cy = overlayHeight / 2
return Rect(
(cx - boxWidth / 2).roundToInt(),
(cy - boxHeight / 2).roundToInt(),
(cx + boxWidth / 2).roundToInt(),
(cy + boxHeight / 2).roundToInt()
)
}
override fun draw(canvas: Canvas) {
super.draw(canvas)
boxRect?.let {
// Draws the dark background scrim and leaves the box area clear.
canvas.drawRect(0f, 0f, width.toFloat(), height.toFloat(), scrimPaint)
// As the stroke is always centered, so erase twice with FILL and STROKE respectively to clear
// all area that the box rect would occupy.
eraserPaint.style = Paint.Style.FILL
canvas.drawRoundRect(it, boxCornerRadius, boxCornerRadius, eraserPaint)
eraserPaint.style = Paint.Style.STROKE
canvas.drawRoundRect(it, boxCornerRadius, boxCornerRadius, eraserPaint)
// Draws the box.
canvas.drawRoundRect(it, boxCornerRadius, boxCornerRadius, boxPaint)
}
}
}
Then in the Analyzer i try to use the data about the boxRect in the way to check if the barcode boudings are contained:
@ExperimentalGetImage
override fun analyze(imageProxy: ImageProxy) {
val mediaImage = imageProxy.image
if (mediaImage != null && !isScanning) {
val image = InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees)
isScanning = true
scanner.process(image)
.addOnSuccessListener { barcodes ->
barcodes.firstOrNull().let { barcode ->
val bounds = barcode?.boundingBox // This is a Rect object
bounds?.let {
viewFinder?.let {
if (viewFinder.contains(bounds)) { // Here i check if the barcode is contained in the ViewFinder box
barcode.rawValue?.let { rawValue ->
if (barcode.format == Barcode.FORMAT_CODE_39) {
val code32 = Utils.code39ToCode32(rawValue)
listener.onScanned(code32)
} else {
listener.onScanned(rawValue)
}
}
}
}
}
}
isScanning = false
imageProxy.close()
}
.addOnFailureListener {
// Task failed with an exception
// ...
isScanning = false
imageProxy.close()
}
}
}
Then in the fragment all is set in that way:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.overlay.post {
binding.overlay.setViewFinder()
}
...
}
private fun bindPreview() {
val cameraProvider = cameraProvider ?: throw IllegalStateException("Camera initialization failed.")
...
val analyzer: ImageAnalysis.Analyzer = MLKitBarcodeAnalyzer(ScanningListener(), binding.overlay.getViewFinder())
imageAnalysis.setAnalyzer(cameraExecutor, analyzer)
...
}
The issue is that the .contains()
check is never successful.
Update:
In a view like the one in the screenshot, the coordinates results like:
viewFinder: Rect(108, 647 - 972, 1376), bounds: Rect(751, 1673 - 1442, 2052)
Have you looked at the coordinates of the bounding box and the viewfinder to see if it’s just a matter of differences in scale or something like that?
@Michael the differenze if huge: viewFinder: Rect(108, 647 – 972, 1376), bounds: Rect(295, 1748 – 785, 2051) But i had to change the code as getViewFinder was returning null, so I’ve just updated the code where i build the Rect based on same data from setViewFinder.