在某些设备上最新的CameraX和条形码扫描存在问题

时间:2020-11-10 07:16:20

标签: android android-camerax google-mlkit

因此,我正在开发一个需要QR扫描仪作为主要功能的应用程序。以前,我在带Firebase ML vision 24.0.3的情况下使用camerax-alpha06,它们工作了好几个月,没有客户抱怨扫描问题。

然后大约两周前,我不得不将Firebase ML视觉更改为MLKit条码扫描(与Crashlytics迁移有关-不在主题之列),现在一些可以在以前版本中进行扫描的用户现在无法使用。一些示例设备是Samsung Tab A7(Android 5.1.1)和Vivo 1919(Android 10)

这是我涉及此功能的build.gradle部分

 def camerax_version = "1.0.0-beta11"
    implementation "androidx.camera:camera-core:${camerax_version}"
    implementation "androidx.camera:camera-camera2:${camerax_version}"
    implementation "androidx.camera:camera-lifecycle:${camerax_version}"
    implementation "androidx.camera:camera-view:1.0.0-alpha18"
    implementation "androidx.camera:camera-extensions:1.0.0-alpha18"
    implementation 'com.google.android.gms:play-services-mlkit-barcode-scanning:16.1.2'

这是我的相机处理程序文件

class ScanQRCameraViewHandler(
    private val fragment: ScanQRDialogFragment,
    private val previewView: PreviewView
) {
    private val displayLayout get() = previewView
    companion object {
        private const val RATIO_4_3_VALUE = 4.0 / 3.0
        private const val RATIO_16_9_VALUE = 16.0 / 9.0
    }

    private val analyzer = GMSMLKitAnalyzer(onFoundQR = { extractedString ->
        fragment.verifyExtractedString(extractedString)
    }, onNotFoundQR = {
        resetStateToAllowNewImageStream()
    })
    private var cameraProviderFuture: ListenableFuture<ProcessCameraProvider>? = null
    private var camera: Camera? = null
    private var isAnalyzing = false

    internal fun resetStateToAllowNewImageStream() {
        isAnalyzing = false
    }

    internal fun setTorceEnable(isEnabled: Boolean) {
        camera?.cameraControl?.enableTorch(isEnabled)
    }

    internal fun initCameraProviderIfHasNot() {
        if (cameraProviderFuture == null) {
            fragment.context?.let {
                cameraProviderFuture = ProcessCameraProvider.getInstance(it)
                val executor = ContextCompat.getMainExecutor(it)
                cameraProviderFuture?.addListener({
                    bindPreview(cameraProviderFuture?.get(), executor)
                }, executor)
            }
        }
    }

    private fun bindPreview(cameraProvider: ProcessCameraProvider?, executor: Executor) {
        val metrics = DisplayMetrics().also { displayLayout.display.getRealMetrics(it) }
        val screenAspectRatio = aspectRatio(metrics.widthPixels, metrics.heightPixels)

        val preview = initPreview(screenAspectRatio)
        val imageAnalyzer = createImageAnalyzer()
        val imageAnalysis = createImageAnalysis(executor, imageAnalyzer, screenAspectRatio)
        val cameraSelector = createCameraSelector()

        cameraProvider?.unbindAll()
        camera = cameraProvider?.bindToLifecycle(
            fragment as LifecycleOwner,
            cameraSelector, imageAnalysis, preview
        )
    }

    private fun createCameraSelector(): CameraSelector {
        return CameraSelector.Builder()
            .requireLensFacing(CameraSelector.LENS_FACING_BACK)
            .build()
    }

    private fun createImageAnalysis(
        executor: Executor, imageAnalyzer: ImageAnalysis.Analyzer, screenAspectRatio: Int
    ): ImageAnalysis {
        val rotation = displayLayout.rotation
        val imageAnalysis = ImageAnalysis.Builder()
//            .setTargetRotation(rotation.toInt())
//            .setTargetAspectRatio(screenAspectRatio)
            .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
            .build()

        imageAnalysis.setAnalyzer(executor, imageAnalyzer)
        return imageAnalysis
    }

    private fun createImageAnalyzer(): ImageAnalysis.Analyzer {
        return ImageAnalysis.Analyzer {
            isAnalyzing = true
            analyzer.analyze(it)
        }
    }

    private fun initPreview(screenAspectRatio: Int): Preview {

        val preview: Preview = Preview.Builder()
            //.setTargetResolution(Size(840, 840))
          //  .setTargetAspectRatio(screenAspectRatio)
          //  .setTargetRotation(displayLayout.rotation.toInt())
            .build()
        preview.setSurfaceProvider(previewView.surfaceProvider)
        return preview
    }

    fun unbindAll() {
        cameraProviderFuture?.get()?.unbindAll()
    }


    private fun aspectRatio(width: Int, height: Int): Int {
        val previewRatio = width.coerceAtLeast(height).toDouble() / width.coerceAtMost(height)
        if (kotlin.math.abs(previewRatio - RATIO_4_3_VALUE) <= kotlin.math.abs(previewRatio - RATIO_16_9_VALUE)) {
            return AspectRatio.RATIO_4_3
        }
        return AspectRatio.RATIO_16_9
    }
}

还有我的分析仪

internal class GMSMLKitAnalyzer(
    private val onFoundQR: (String) -> Unit,
    private val onNotFoundQR: () -> Unit
) :
    ImageAnalysis.Analyzer {

    private val options = BarcodeScannerOptions.Builder()
        .setBarcodeFormats(Barcode.FORMAT_QR_CODE).build()

    @SuppressLint("UnsafeExperimentalUsageError")
    override fun analyze(imageProxy: ImageProxy) {
        imageProxy.image?.let { mediaImage ->
            val image = InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees)
            val scanner = BarcodeScanning.getClient(options)
            CoroutineScope(Dispatchers.Main).launch {
                val result = scanner.process(image).await()
                result.result?.let { barcodes ->
                    barcodes.find { it.rawValue != null }?.rawValue?.let {
                        onFoundQR(it)
                    } ?: run { onNotFoundQR() }
                }
                imageProxy.close()
            }
        } ?: imageProxy.close()

    }
}

注释掉的行是我尝试添加但没有帮助的内容,其中一些甚至在其他(待使用的)设备上引起了问题。

我不确定是否配置有误,所以我希望有任何建议可以帮助我找到解决方案。

谢谢

P.S。这是我的第一篇文章,因此,如果我做错了任何事情或错过了一些事情,请提出建议。

1 个答案:

答案 0 :(得分:1)

BarcodeScanning在某些运行camera-camera2:1.0.0-beta08版本或更高版本的设备上不起作用。您可以使用早期版本的camera-camera2来绕过此问题。例如:

请参阅:https://developers.google.com/ml-kit/known-issues 对于下一个SDK版本,我们正在MLKit内部进行修复。

相关问题