Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(Android) Add support to detect QR codes only when inside a frame #693

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

rawatnaresh
Copy link

Summary

This PR fixes #689 and #484 based on the suggestions from #484 (comment).
Let me know if there's anything that needs to be improve in this PR—I’m happy to make changes!. Thanks.

How did you test this change?

VID_20250122_140752.mp4

Copy link
Contributor

@DavidBertet DavidBertet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @rawatnaresh for your first contribution!

I left a few feedbacks, but it's looking good

Comment on lines 315 to 318
val barcodeBoundingBox = barcode.boundingBox
if (barcodeBoundingBox === null) {
return@filter false
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can write that in one line. This will return early if variable is null

Suggested change
val barcodeBoundingBox = barcode.boundingBox
if (barcodeBoundingBox === null) {
return@filter false
}
val barcodeBoundingBox = barcode.boundingBox ?: return@filter false

}

// val scaleX = viewFinder.width.toFloat() / imageSize.width
// val scaleY = viewFinder.height.toFloat() / imageSize.height
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be removed

)

// Check if the scaled bounding box is within the frame rectangle
barcodeFrame?.frameRect!!.contains(scaledBarcodeBoundingBox)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid !! that would crash the app, prefer ? that would gracefully do nothing

But barcodeFrame shouldn't be optional as we check for it at the beginning, you might be able to remove it

Suggested change
barcodeFrame?.frameRect!!.contains(scaledBarcodeBoundingBox)
barcodeFrame.frameRect.contains(scaledBarcodeBoundingBox)

) : ImageAnalysis.Analyzer {
@SuppressLint("UnsafeExperimentalUsageError")
@ExperimentalGetImage
override fun analyze(image: ImageProxy) {
val inputImage = InputImage.fromMediaImage(image.image!!, image.imageInfo.rotationDegrees)
val mediaImage = image.image ?: return
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

class QRCodeAnalyzer (
private val onQRCodesDetected: (qrCodes: List<Barcode>) -> Unit
class QRCodeAnalyzer(
private val onQRCodesDetected: (qrCodes: List<Pair<Barcode, Size>>) -> Unit
Copy link
Contributor

@DavidBertet DavidBertet Jan 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my comment, I was suggesting using a Pair to store the barcode bounding box. Turns out it's already in the Barcode object itself!

Here, as the imageSize is the same for every barcodes, I would sent it as another parameter, next to the barcodes

Suggested change
private val onQRCodesDetected: (qrCodes: List<Pair<Barcode, Size>>) -> Unit
private val onQRCodesDetected: (qrCodes: List<Barcode>, imageSize: Size) -> Unit

This simplifies the code above, as the scale can be computed only once, and we don't have to "extract only the barcodes"
And below as we can just call onQRCodesDetected(result, Size(...)) without the map

Comment on lines 311 to 313
val analyzer = QRCodeAnalyzer { results ->
if (results.isNotEmpty()) {
val filteredResults = if (barcodeFrame !== null) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We rarely, if ever, use triple equality in Kotlin. Same below with ===, prefer == instead

You can also create a shadow copy of barcodeFrame. This is not very sexy, but barcodeFrame is now a local val, and the compiler will allow using it later as a non optional.

Lastly, reverting the condition makes the code easier to read as we avoid having a one line else 20 lines down

That could looks something like that, with imageSize moved out

Suggested change
val analyzer = QRCodeAnalyzer { results ->
if (results.isNotEmpty()) {
val filteredResults = if (barcodeFrame !== null) {
val analyzer = QRCodeAnalyzer { (barcodes, imageSize) ->
if (barcodes.isEmpty()) {
return@QRCodeAnalyzer
}
val barcodeFrame = barcodeFrame
if (barcodeFrame == null) {
onBarcodeRead(barcodes)
return@QRCodeAnalyzer
}
val filteredBarcodes = barcodes.filter { barcode ->
...
}
onBarcodeRead(filteredBarcodes)

@rawatnaresh
Copy link
Author

Hi @DavidBertet, thank you for your explanations and suggestions. I've made the changes accordingly. Please take a look

Copy link
Contributor

@DavidBertet DavidBertet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! Thank you @rawatnaresh

PS: You might have a few linter issue, like space after if.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Read QR code inside frame area not working on Android
2 participants