首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用于QR代码扫描的Android工具包库:如何通过降低图像分辨率来提高检测性能

用于QR代码扫描的Android工具包库:如何通过降低图像分辨率来提高检测性能
EN

Stack Overflow用户
提问于 2022-06-27 05:45:15
回答 2查看 611关注 0票数 0

这是我剥离的条形码扫描源代码

build.gradle

代码语言:javascript
复制
dependencies {
    .....
     // MLKit Dependencies
    implementation 'com.google.android.gms:play-services-vision:20.1.3'

    implementation 'com.google.mlkit:barcode-scanning:17.0.2'
    def camerax_version = "1.1.0-beta01"
    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-video:${camerax_version}" 
    ......
}

ScanCameraFragment.kt

代码语言:javascript
复制
class ScanCameraFragment : BaseFragment() {
    private lateinit var binding: FragmentScanCameraBinding
    private lateinit var cameraExecutor: ExecutorService

    //region Lifecycle Methods
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?): View? {
        binding = FragmentScanCameraBinding.inflate(inflater, container, false)
        cameraExecutor = Executors.newSingleThreadExecutor()

        startCamera()
        return binding.root
    }

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

    companion object {
        fun newInstance() = ScanCameraFragment().apply {}
    }

    private fun startCamera() {
        context?.let { context ->
            val cameraProviderFuture = ProcessCameraProvider.getInstance(context)

            cameraProviderFuture.addListener({
                val cameraProvider = cameraProviderFuture.get()

                // Preview
                val preview = Preview.Builder()
                    .build()
                    .also {
                        it.setSurfaceProvider(binding.previewView.surfaceProvider)
                    }

                // Image analyzer
                val imageAnalyzer = ImageAnalysis.Builder()
                    .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
                    .build()
                    .also {
                        it.setAnalyzer(cameraExecutor,
                            QrCodeAnalyzer(context, binding.barcodeBoxView,
                                      binding.previewView.width.toFloat(), 
                                      binding.previewView.height.toFloat()
                            )
                        )
                    }

                // Select back camera as a default
                val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA

                try {
                    // Unbind use cases before rebinding
                    cameraProvider.unbindAll()

                    // Bind use cases to camera
                    var camera = cameraProvider.bindToLifecycle(this, cameraSelector,
                                      preview, imageAnalyzer)

                } catch (exc: Exception) {
                    exc.printStackTrace()
                }
            }, ContextCompat.getMainExecutor(context))
        }
    }
}

QRCodeAnalyzer.kt

代码语言:javascript
复制
class QrCodeAnalyzer(private val context: Context, 
    private val barcodeBoxView: BarcodeBoxView, private val previewViewWidth: Float,
    private val previewViewHeight: Float) : ImageAnalysis.Analyzer {

    private var scaleX = 1f
    private var scaleY = 1f

    private fun translateX(x: Float) = x * scaleX
    private fun translateY(y: Float) = y * scaleY

    private fun adjustBoundingRect(rect: Rect) = RectF(
        translateX(rect.left.toFloat()),
        translateY(rect.top.toFloat()),
        translateX(rect.right.toFloat()),
        translateY(rect.bottom.toFloat())
    )

    @SuppressLint("UnsafeOptInUsageError")
    override fun analyze(image: ImageProxy) {
        val img = image.image
        if (img != null) {
            // Update scale factors
            scaleX = previewViewWidth / img.height.toFloat()
            scaleY = previewViewHeight / img.width.toFloat()

            val inputImage = InputImage.fromMediaImage(img, 
                                image.imageInfo.rotationDegrees)

            // Process image searching for barcodes
            val options = BarcodeScannerOptions.Builder()
                .build()
            val scanner = BarcodeScanning.getClient(options)
            scanner.process(inputImage)
                .addOnSuccessListener { barcodes ->
                    for (barcode in barcodes) {
                        barcode?.rawValue?.let {
                            if (it.trim().isNotBlank()) {
                                Scanner.updateBarcode(it)
                                barcode.boundingBox?.let { rect ->
                                    barcodeBoxView.setRect(adjustBoundingRect(rect))
                                }
                            }
                            return@addOnSuccessListener
                        }
                    }
                    // coming here means no satisfiable barcode was found
                    barcodeBoxView.setRect(RectF())
                }
                .addOnFailureListener {
                    image.close()
                }
                .addOnFailureListener { }
        }

        image.close()
    }
}

这个代码工作,我可以扫描条形码。但有时条形码检测很慢。文档说,提高性能的一种方法是限制图像分辨率。

不要在摄像机的本机分辨率上捕捉输入。在某些设备上,以本机分辨率捕获输入会产生非常大(10+百万像素)的图像,这会导致很低的延迟,而对准确性没有好处。相反,只要求相机的大小,这是条形码检测所需的,通常不超过200万像素。 如果扫描速度重要,则可以进一步降低图像捕获分辨率。但是,请记住上面概述的最低条形码大小要求。

不幸的是,文档没有指定如何降低图像分辨率。我的一些终端用户使用的是带有强大摄像头的高端设备,因此我们假设性能较差的原因是图像大小。

如何将图像的分辨率降低到固定值(类似于1024x768),而不是默认的相机分辨率?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-06-29 06:39:28

用户HarmenH的答案正确地告诉如何设置图像分辨率,所以我在这里不再重复。

事实证明,我的性能问题并不是因为图像分辨率。我似乎过早地关闭了imageProxy。

代码语言:javascript
复制
override fun analyze(image: ImageProxy) {
    val img = image.image
    if (img != null) {
        // Update scale factors
        scaleX = previewViewWidth / img.height.toFloat()
        scaleY = previewViewHeight / img.width.toFloat()

        val inputImage = InputImage.fromMediaImage(img,
            image.imageInfo.rotationDegrees)

        // Process image searching for barcodes
        val options = BarcodeScannerOptions.Builder()
            .build()
        val scanner = BarcodeScanning.getClient(options)
        scanner.process(inputImage)
            .addOnSuccessListener { barcodes - >
                for (barcode in barcodes) {
                    barcode?.rawValue?.let {
                       if (it.trim().isNotBlank()) {
                           Scanner.updateBarcode(it)
                           barcode.boundingBox?.let { rect - >
                              barcodeBoxView.setRect(adjustBoundingRect(rect))
                           }
                       }
                       return @addOnSuccessListener
                    }
                }
                // coming here means no satisfiable barcode was found
                barcodeBoxView.setRect(RectF())
            }
            .addOnFailureListener {
                image.close()
            }
            .addOnFailureListener {
                //added this here.
                image.close()
            }
    }
    //Removed this because we don't close the 
    //imageProxy before analysis completes
    //image.close()
}
票数 1
EN

Stack Overflow用户

发布于 2022-06-27 07:20:48

可以在imageAnalyzer构建器bij上使用.setTargetResolution(大小)设置它。

代码语言:javascript
复制
val imageAnalysisUseCaseBuilder = ImageAnalysis.Builder()
imageAnalysisUseCaseBuilder.setTargetResolution(Size(1024, 768))
    
imageAnalysisUseCase = imageAnalysisUseCaseBuilder.build()

或者在你的情况下

代码语言:javascript
复制
val imageAnalyzer = ImageAnalysis.Builder()
    .setTargetResolution(Size(1024, 768))
    .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
    .build()
    .also {
        it.setAnalyzer(cameraExecutor,
            QrCodeAnalyzer(context, binding.barcodeBoxView,
                binding.previewView.width.toFloat(), 
                binding.previewView.height.toFloat()
            )
        )
    }
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72767423

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档