Android mlkit 条码扫描仪提高速度

问题描述 投票:0回答:3

你好我正在使用没有 firebase 和 androidx 的 android mlkit 条码扫描器,我遵循这个代码https://medium.com/@surya.n1447/google-vision-ml-kit-with-camerax-64bbbfd4c6fd 我扫描二维码的时候太慢了,我不知道如何提高扫描速度,有没有什么技巧之类的?还是改用 zxing 或 Google vision 更好? 我用的是小米 10 t pro

ScanPersonFragment 类:片段(){

private var processingBarcode = AtomicBoolean(false)
private var mediaPlayer: MediaPlayer? = null
private lateinit var cameraExecutor: ExecutorService
private lateinit var scanBarcodeViewModel: ScanPersonViewModel


override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    cameraExecutor = Executors.newSingleThreadExecutor()
    scanBarcodeViewModel = ViewModelProvider(this).get(ScanPersonViewModel::class.java)
}

override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    val v = inflater.inflate(R.layout.fragment_scan_person_destination, container, false)
    mediaPlayer = MediaPlayer.create(context, R.raw.beep)
    scanBarcodeViewModel.progressState.observe(viewLifecycleOwner, {
        v.fragment_scan_person_barcode_progress_bar.visibility = if (it) View.VISIBLE else View.GONE
    })

    scanBarcodeViewModel.navigation.observe(viewLifecycleOwner, { navDirections ->
        navDirections?.let {
            findNavController().navigate(navDirections)
            scanBarcodeViewModel.doneNavigating()
        }
    })

    return v
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    if (allPermissionsGranted()) {
        startCamera()
    } else {
        requestPermissions(
            REQUIRED_PERMISSIONS,
            REQUEST_CODE_PERMISSIONS
        )
    }
}

override fun onResume() {
    super.onResume()
    processingBarcode.set(false)
}

private fun startCamera() {
    // Create an instance of the ProcessCameraProvider,
    // which will be used to bind the use cases to a lifecycle owner.
    val cameraProviderFuture = ProcessCameraProvider.getInstance(requireContext())




    val imageCapture = ImageCapture.Builder()
        .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
        //.setTargetResolution(Size(400, 400))
        .build()

    // Add a listener to the cameraProviderFuture.
    // The first argument is a Runnable, which will be where the magic actually happens.
    // The second argument (way down below) is an Executor that runs on the main thread.
    cameraProviderFuture.addListener({
        // Add a ProcessCameraProvider, which binds the lifecycle of your camera to
        // the LifecycleOwner within the application's life.
        val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
        // Initialize the Preview object, get a surface provider from your PreviewView,
        // and set it on the preview instance.
        val preview = Preview.Builder().build().also {
            it.setSurfaceProvider(
                fragment_scan_person_barcode_preview_view.surfaceProvider
            )
        }
        // Setup the ImageAnalyzer for the ImageAnalysis use case
        val imageAnalysis = ImageAnalysis.Builder()
            .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
            .build()
            .also {
                it.setAnalyzer(cameraExecutor, BarcodeAnalyzer { barcode ->
                    if (processingBarcode.compareAndSet(false, true)) {
                        mediaPlayer?.start()
                        searchBarcode(barcode)
                    }
                })
            }

        // Select back camera
        val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
        try {
            // Unbind any bound use cases before rebinding
            cameraProvider.unbindAll()
            // Bind use cases to lifecycleOwner
            cameraProvider.bindToLifecycle(this, cameraSelector, preview,  imageAnalysis)
        } catch (e: Exception) {
            Log.e("PreviewUseCase", "Binding failed! :(", e)
        }
    }, ContextCompat.getMainExecutor(requireContext()))
}

private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all {
    ContextCompat.checkSelfPermission(
        requireContext(), it
    ) == PackageManager.PERMISSION_GRANTED
}

override fun onRequestPermissionsResult(
    requestCode: Int, permissions: Array<String>, grantResults:
    IntArray
) {
    if (requestCode == REQUEST_CODE_PERMISSIONS) {
        if (allPermissionsGranted()) {
            startCamera()
        } else {
            Toast.makeText(
                requireContext(),
                "Permissions not granted by the user.",
                Toast.LENGTH_SHORT
            ).show()
        }
    }
}

private fun searchBarcode(barcode: String) {
    scanBarcodeViewModel.searchBarcode(barcode)
}

override fun onDestroy() {
    cameraExecutor.shutdown()
    super.onDestroy()
}

companion object {
    private val REQUIRED_PERMISSIONS = arrayOf(Manifest.permission.CAMERA)
    private const val REQUEST_CODE_PERMISSIONS = 10
}

类 BarcodeAnalyzer(私有 val barcodeListener:BarcodeListener):ImageAnalysis.Analyzer {

@SuppressLint("UnsafeExperimentalUsageError")
override fun analyze(imageProxy: ImageProxy) {
    val mediaImage = imageProxy.image
    if (mediaImage != null) {
        val image = InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees)
        val options = BarcodeScannerOptions.Builder().setBarcodeFormats(Barcode.FORMAT_QR_CODE).build()
        val scanner = BarcodeScanning.getClient(options)
        // Pass image to the scanner and have it do its thing
        scanner.process(image)
            .addOnSuccessListener { barcodes ->
                // Task completed successfully
                for (barcode in barcodes) {

                    barcodeListener(barcode.rawValue ?: "")
                }
            }
            .addOnFailureListener {
                // You should really do something about Exceptions
            }
            .addOnCompleteListener {
                // It's important to close the imageProxy
                imageProxy.close()
            }
    }
}

}

android computer-vision android-camera firebase-mlkit google-mlkit
3个回答
5
投票

总结一些答案:

  • 对于非常大的图像,比如 108 兆像素的相机,降低分辨率很有帮助。对于典型用途,我们发现 1280x720 或 1920x1080 分辨率就足够了。

  • 近期尝试使用条码模型V2的“捆绑”版条码SDK:

    implementation 'com.google.mlkit:barcode-scanning:16.1.0'
    

    Barcode V2 实施速度更快、更准确,但作为“捆绑”模型,它会增加大约 2.2 MB 的应用程序大小。团队致力于将其引入 Google Play 服务版本(即非捆绑),并在未来几个月内消除应用程序捆绑 2.2 MB 模型的需要。

    有关捆绑版本和非捆绑版本之间的更多信息,请查看本页顶部的表格


1
投票

首先将图像代理转换为位图。 其次不要忘记关闭图像代理。然后它会提高性能。

if (image.image != null && image.format == ImageFormat.YUV_420_888) {
                


                scanner.process(InputImage.fromBitmap(image.toBitmap(), image.imageInfo.rotationDegrees))
                    .addOnSuccessListener { barcodes ->
                        if (barcodes.isNotEmpty()) {

                            if (firstCall){


                                for (barcode in barcodes) {
                                    

                                    // Handle received barcodes...


                                    Log.d("ValueXXXX ",barcode.format.toString())

                                    if (barcode.format==Barcode.FORMAT_QR_CODE){
                                        var data = barcode.displayValue.toString().replace("\\", "")
                                        //var json=org.json.JSONObject(data)

                                        Log.d("TAG","DATA1111 "+data)

                                        if(Utils.urlPattern.matcher(data).matches()) {
                                            firstCall=false


                                            showPopupForInvalidQRCode(R.string.DISPLAY_INVALID_QR_CODE,context)



                                            break
                                        }
                                        if (!data.isNullOrEmpty() && Utils.isJSONValid(data)){
                                            firstCall=false
                                            try {
                                                val json = JSONObject(data)
                                                Log.d("TAG","json "+json)
                                                val vibrator = context?.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
                                                    if (Build.VERSION.SDK_INT >= 26) {
                                                        vibrator.vibrate(VibrationEffect.createOneShot(300, VibrationEffect.DEFAULT_AMPLITUDE))
                                                    } else {
                                                        vibrator.vibrate(300)
                                                    }

                                                 //parse your json here   

                                                break
                                            }catch (e:Exception){
                                                e.printStackTrace()
                                                showPopupForInvalidQRCode(R.string.DISPLAY_INVALID_QR_CODE,context)
                                            }
                                        }

                                        break
                                    }



                                }
                            }

                        } else {
                            // Remove bounding rect
                            barcodeBoxView.setRect(RectF())
                        }
                    }
                    .addOnFailureListener {
                        firstCall=true
                        Log.d("EXCEPTION",it.message.toString())
                        //image.close()

                    }
                    

                    }
            }

0
投票

这对我来说很重要!

请注意在成功或失败后关闭 ImageProxy 和 Image否则代码将只运行一次,它只触发一次而忘记。

image.image?.close() image.close()
    
© www.soinside.com 2019 - 2024. All rights reserved.