如何使用Firebase ML Kit识别条形码?

3
我正在尝试在我的应用程序中打开相机时识别QR码,然后根据QR码文本转移到相应的活动页面。我使用Firebase ML Kit和CameraX库结合Google文档进行操作,但是在ImageAnalyzer的analyze方法中出现了错误。 ImageAnalyzer要求我实现analyze方法,即使它已经被实现了。但是它有两个参数:(imageProxy:ImageProxy?,degrees:Int)并且说它没有覆盖任何东西。如果我删除第二个参数(degrees:Int),则可以识别,但“度数”未被识别。
我尝试关注一些教程,但他们使用了很多第三方库。我想使用cameraX和ML Kit。
如何解决这个问题?
以下是我的代码:
package ge.softservice.nfcwithactivties

import android.Manifest
import android.annotation.SuppressLint
import android.content.pm.PackageManager
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.camera.core.*
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.google.firebase.ml.vision.FirebaseVision
import com.google.firebase.ml.vision.barcode.FirebaseVisionBarcode
import com.google.firebase.ml.vision.barcode.FirebaseVisionBarcodeDetectorOptions
import com.google.firebase.ml.vision.common.FirebaseVisionImage
import com.google.firebase.ml.vision.common.FirebaseVisionImageMetadata
import kotlinx.android.synthetic.main.activity_qr.*
import java.io.File
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors


class QrActivity : AppCompatActivity() {
    private var preview: Preview? = null
    private var imageAnalyzer: ImageAnalysis? = null
    private var camera: Camera? = null

    internal var isDetected = false

    private lateinit var outputDirectory: File
    private lateinit var cameraExecutor: ExecutorService
    override fun onRequestPermissionsResult(
        requestCode: Int, permissions: Array<String>, grantResults:
        IntArray
    ) {
        if (requestCode == REQUEST_CODE_PERMISSIONS) {
            if (allPermissionsGranted()) {
                startCamera()
            } else {
                Toast.makeText(
                    this,
                    "Permissions not granted by the user.",
                    Toast.LENGTH_SHORT
                ).show()
                finish()
            }
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_qr)

        // Request camera permissions
        if (allPermissionsGranted()) {
            startCamera()
        } else {
            ActivityCompat.requestPermissions(
                this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS
            )
        }

        //      outputDirectory = getOutputDirectory()

        cameraExecutor = Executors.newSingleThreadExecutor()
    }

    private fun startCamera() {

        val options = FirebaseVisionBarcodeDetectorOptions.Builder()
            .setBarcodeFormats(
                FirebaseVisionBarcode.FORMAT_QR_CODE,
                FirebaseVisionBarcode.FORMAT_AZTEC
            )
            .build()
        val detector = FirebaseVision.getInstance().getVisionBarcodeDetector(options)
        val result = detector.detectInImage(image)
            .addOnSuccessListener { barcodes ->
                // Task completed successfully
                // ...
            }
            .addOnFailureListener {
                // Task failed with an exception
                // ...
            }
        val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
        cameraProviderFuture.addListener(Runnable {
            // Used to bind the lifecycle of cameras to the lifecycle owner
            val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()

            // Preview
            preview = Preview.Builder()
                .build()

            // Select back camera
            val cameraSelector =
                CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build()

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

                // Bind use cases to camera
                camera = cameraProvider.bindToLifecycle(
                    this, cameraSelector, preview
                )
                preview?.setSurfaceProvider(viewFinder.createSurfaceProvider(/*camera?.cameraInfo*/))
            } catch (exc: Exception) {
                Log.e(TAG, "Use case binding failed", exc)
            }

        }, ContextCompat.getMainExecutor(this))
    }

    private fun takePhoto() {
        // TODO
    }

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

/*    fun getOutputDirectory(): File {
        val mediaDir = externalMediaDirs.firstOrNull()?.let {
            File(it, resources.getString(R.string.app_name)).apply { mkdirs() } }
        return if (mediaDir != null && mediaDir.exists())
            mediaDir else filesDir
    }*/

    companion object {
        private const val TAG = "CameraXBasic"
        private const val FILENAME_FORMAT = "yyyy-MM-dd-HH-mm-ss-SSS"
        private const val REQUEST_CODE_PERMISSIONS = 10
        private val REQUIRED_PERMISSIONS = arrayOf(Manifest.permission.CAMERA)
    }
}

private class MyImageAnalyzer : ImageAnalysis.Analyzer {
    private fun degreesToFirebaseRotation(degrees: Int): Int = when(degrees) {
        0 -> FirebaseVisionImageMetadata.ROTATION_0
        90 -> FirebaseVisionImageMetadata.ROTATION_90
        180 -> FirebaseVisionImageMetadata.ROTATION_180
        270 -> FirebaseVisionImageMetadata.ROTATION_270
        else -> throw Exception("Rotation must be 0, 90, 180, or 270.")
    }

    @SuppressLint("UnsafeExperimentalUsageError")
    override fun analyze(imageProxy: ImageProxy?, degrees: Int) {
        val mediaImage = imageProxy?.image
        val imageRotation = degreesToFirebaseRotation(degrees)
        if (mediaImage != null) {
            val image = FirebaseVisionImage.fromMediaImage(mediaImage, imageRotation)
            // Pass image to an ML Kit Vision API
            // ...
        }
    }
}
1个回答

2

从您的代码片段来看,似乎您正在使用相机-camera2版本beta04和camerax-view版本alpha11。

文档可能已经过时,现在Analyzer仅在其analyze回调中接收一个ImageProxy。之前传递的度数信息现在可以通过ImageProxy.getImageInfo().getRotationDegrees()访问。

因此,您的分析器应该像这样:

private class MyImageAnalyzer : ImageAnalysis.Analyzer {

    private fun degreesToFirebaseRotation(degrees: Int): Int {
        // ...
    }

    override fun analyze(imageProxy: ImageProxy) {
        val mediaImage = imageProxy.image
        val imageRotation = degreesToFirebaseRotation(imageProxy.imageInfo.rotationDegrees)
        val image = FirebaseVisionImage.fromMediaImage(mediaImage, imageRotation)
        // ...
    }
}

谢谢。我会尝试的。 - X Y
在这一行代码中:val imageRotation = degreesToFirebaseRotation(imageProxy.image.rotationDegrees),rotationDegrees被标记为未解决的引用。如果我将其更改为degrees,情况也是一样的。我该如何访问degreesToFirebaseRotation函数的degrees参数? - X Y
1
抱歉,有个打字错误。我更新了答案,现在应该可以工作了。 - Husayn Hakeem
现在在MyImageAnalyzer类中没有错误,但是在QrActivity类中的图像值(val result = detector.detectInImage(image))无法识别。我在github上找到了类似的项目:https://github.com/Lavanyagaur22/Visitor-Card,但是不知道如何将其适配到我的项目中。我还将选项、检测器和结果变量转移到了MyImage类中,现在没有错误,但是如何将结果值连接到QrActivity呢?为了更清楚地说明,也许最好在stackoverflow上提出新问题。 - X Y
degreesToFirebaseRotation 是什么意思? - user924

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