Android MLKit仅在屏幕中心扫描QR码

3

我使用Firebase MLKit实现了QR码扫描功能,它可以进行扫描,但是会扫描屏幕上所有的QR码。

我需要仅扫描位于中心位置的QR码(即带有箭头图像视图的QR码),请问该如何实现?

我尝试在Analysis函数(在analysisUseCase?.setAnalyzer内)中裁剪:

imageProxy.cropRect()

我还尝试在processImageProxy函数中进行裁剪,但没有成功,我认为无法通过这种方法进行裁剪。

class QrcodeScanner(
        private val onQrCapture: Barcode.() -> Unit,
        private val onFailure: Throwable.() -> Unit,
        private val lifecycleOwner: LifecycleOwner,
        private val context: Context,
        private val previewView: PreviewView
) {

    private var cameraSelector: CameraSelector = CameraSelector.Builder()
            .requireLensFacing(CameraSelector.LENS_FACING_BACK)
            .build()
    private var cameraProvider: ProcessCameraProvider? = null
    private var previewUseCase: Preview? = null
    private var analysisUseCase: ImageAnalysis? = null

    fun startCamera() {
        val cameraProviderFuture =
                ProcessCameraProvider.getInstance(context)
        cameraProviderFuture.addListener(
                {
                    runCatching {
                        val provider = cameraProviderFuture.get()
                        cameraProvider = provider
                        startPreview()
                        startAnalysis()
                    }.onFailure {
                        onFailure(it)
                    }
                },
                ContextCompat.getMainExecutor(context)
        )
    }

    private fun startPreview() {
        if (previewUseCase != null) {
            cameraProvider?.unbind(previewUseCase)
        }

        previewUseCase = Preview.Builder()
                .setTargetRotation(previewView.display.rotation)
                .build()
        previewUseCase?.setSurfaceProvider(previewView.surfaceProvider)

        runCatching {
            cameraProvider?.bindToLifecycle(lifecycleOwner,
                    cameraSelector,
                    previewUseCase
            )
        }.onFailure {
            onFailure(it)
        }
    }

    private fun startAnalysis() {
        val options = BarcodeScannerOptions.Builder()
             .setBarcodeFormats(Barcode.FORMAT_QR_CODE)
             .build()
        val barcodeScanner: BarcodeScanner = BarcodeScanning.getClient(options)

        if (cameraProvider == null) {
            return
        }
        if (analysisUseCase != null) {
            cameraProvider?.unbind(analysisUseCase)
        }

        analysisUseCase = ImageAnalysis.Builder()
                .setTargetRotation(previewView.display.rotation)
                .build()

        val cameraExecutor = Executors.newSingleThreadExecutor()

        analysisUseCase?.setAnalyzer(cameraExecutor, ImageAnalysis.Analyzer { imageProxy ->
            processImageProxy(barcodeScanner, imageProxy)
        })

        runCatching {
            cameraProvider?.bindToLifecycle(lifecycleOwner,
                    cameraSelector,
                    analysisUseCase
            )
        }.onFailure {
            onFailure(it)
        }

    }

    @SuppressLint("UnsafeExperimentalUsageError")
    private fun processImageProxy(
            barcodeScanner: BarcodeScanner,
            imageProxy: ImageProxy
    ) {
        runCatching {
            val img = imageProxy.image
            if (img != null) {
                val inputImage =
                        InputImage.fromMediaImage(img, imageProxy.imageInfo.rotationDegrees)

                barcodeScanner.process(inputImage)
                        .addOnSuccessListener { barcodes ->
                            barcodes.forEach {
                                onQrCapture(it)
                            }
                        }
                        .addOnFailureListener {
                            onFailure(it)
                        }.addOnCompleteListener {
                            imageProxy.close()
                        }
            } else {
                throw Exception("Falha ao processar a imagem")
            }
        }.onFailure {
            onFailure(it)
        }

    }

}

嗨,您可以查看我在stackoverflow.com/a/67348548/13300615中提供的解决方案。也许它可以帮助您裁剪图像。 - Alex F.
3个回答

3

imageProxy.cropRect() 方法只是在图像中添加元数据,而不会执行裁剪操作。对于静态图像,您可以将其转换为位图并进行裁剪。更好的方法是在检测到所有返回的条形码和检测到的条形码边界框时过滤结果。

在 MLKit 中,我们正在添加支持图像裁剪的功能。


所以我不能使用裁剪来处理这个问题,我必须使用另一种方法。因为我不是拍照,而是实时扫描QR码...但是我该如何过滤这个结果呢?要在PreviewView(相机)的中心检测QR码。我毫无头绪。 - felipe.rce
3
现在你可以获取检测到的条形码列表,只处理(例如显示检测结果)位于感兴趣区域内的条形码。每个条形码的边界框可以通过Barcode# getBoundingBox()获得。 - Shiyu
请分享 mlkit 条形码扫描的实现。 - ekibet

2
您可以修改BarcodeScannerProcessor类中的onSuccess()方法来检查条形码的四个角落位置。如果它在扫描区域内,则从onSuccess()返回true,如下所示:
protected void onSuccess(List<Barcode> barcodes, GraphicOverlay graphicOverlay) {
    if (barcodes.isEmpty()) {
        Log.v(MANUAL_TESTING_LOG, "No barcode has been detected");
    }

    for (int i = 0; i < barcodes.size(); ++i) {
        Barcode barcode = barcodes.get(i);
        BarcodeGraphic barcodeGraphic = new BarcodeGraphic(graphicOverlay, barcode);

        // check whether within valid scan area, translateX and translateY is to convert to screen position in pixel
        if (barcode.getBoundingBox() != null &&
                withinScanArea(
                    barcodeGraphic.translateY(barcode.getBoundingBox().top),
                    barcodeGraphic.translateX(barcode.getBoundingBox().left),
                    barcodeGraphic.translateY(barcode.getBoundingBox().bottom),
                    barcodeGraphic.translateX(barcode.getBoundingBox().right)
                )
        ) {
            graphicOverlay.add(barcodeGraphic);

            if (barcode.getRawValue() != null && !barcode.getRawValue().isEmpty()) {
                exchangeScannedData.sendScannedCode(barcode.getRawValue());
            }
        }
    }
}

"

scanAreaTop等是本地变量,其值根据您的扫描视图而定。

"
private boolean withinScanArea(float top, float left, float bottom, float right) {
    return top > scanAreaTop &&
           left > scanAreaLeft &&
           bottom < scanAreaBottom &&
           right < scanAreaRight;
}

什么是 BarcodeGraphic 类? - Umberto Covino
BarcodeGraphic绘制检测到的条形码的“原始值”和边界框。 - Chris

0

我最近一直在处理同一个问题,并找到了如何准确过滤imageProxy并仅检测屏幕中央聚焦矩形内的条形码。

我创建了这个存储库,供那些未来可能需要它的人使用 https://github.com/javaherisaber/MLBarcodeScanner


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接