0

我正在尝试制作一个读取 QR 图像并从图像中获取数据的应用程序。我正在使用最新版本的谷歌机器学习工具包扫描条形码,并遵循有关此https://developers.google.com/ml-kit/vision/barcode-scanning/android的文档。

但是,在我运行该应用程序的那一刻,我遇到了以下崩溃:

QR 扫描仪应用程序的图像错误

我不知道这是怎么回事,因为我是具有这种功能的新手。这是我现在使用的代码:

package com.google.firebase.codelab.barcode_scanning

import android.os.Bundle
import android.util.Log
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.camera.core.*
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.mlkit.vision.barcode.Barcode
import com.google.mlkit.vision.barcode.BarcodeScannerOptions
import com.google.mlkit.vision.barcode.BarcodeScanning
import com.google.mlkit.vision.common.InputImage
import kotlinx.android.synthetic.main.activity_main.*
import java.util.concurrent.Executors

class BarcodeScannerActivity : AppCompatActivity() {

    private val qrList = arrayListOf<QrCode>()
    val adapter = QrCodeAdapter(qrList)
    private val executor = Executors.newSingleThreadExecutor()
    private val options = BarcodeScannerOptions.Builder()
            .setBarcodeFormats(
                    Barcode.FORMAT_QR_CODE)
            .build()
    private val scanner = BarcodeScanning.getClient(options)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        rvQrCode.layoutManager = LinearLayoutManager(this)
        rvQrCode.adapter = adapter


        val imageAnalysisConfig = ImageAnalysisConfig.Builder()
                .setImageReaderMode(ImageAnalysis.ImageReaderMode.ACQUIRE_LATEST_IMAGE)
                .build()

        val imageAnalysis = ImageAnalysis(imageAnalysisConfig)

        val previewConfig = PreviewConfig.Builder().apply {
            setLensFacing(CameraX.LensFacing.BACK)
        }.build()

        val preview = Preview(previewConfig)

        preview.setOnPreviewOutputUpdateListener {
            val parent = cameraView.parent as ViewGroup
            parent.removeView(cameraView)
            cameraView.surfaceTexture = it.surfaceTexture
            parent.addView(cameraView, 0)
        }

        val analyzer = ImageAnalysis.Analyzer{ imageProxy: ImageProxy?, rotationDegrees: Int ->
            imageProxy?.let {
                it.image?.let { image ->
                    val inputImage = InputImage.fromMediaImage(image, rotationDegrees)
                    runBarcodeScanner(inputImage)
                    //image.close()
                }
            }
            imageProxy?.close()
        }

        imageAnalysis.setAnalyzer(executor, analyzer)
        CameraX.bindToLifecycle(this, preview, imageAnalysis)
    }


    private fun runBarcodeScanner(image: InputImage) {
        // [START run_detector]
        scanner.process(image)
                .addOnSuccessListener { barcodes ->
                    // Task completed successfully
                    // [START_EXCLUDE]
                    // [START get_barcodes]
                    Log.e("SUCCESS..","OK")
                    for (barcode in barcodes) {
                        val bounds = barcode.boundingBox
                        val corners = barcode.cornerPoints

                        val rawValue = barcode.rawValue

                        val valueType = barcode.valueType
                        // See API reference for complete list of supported types
                        when (valueType) {
                            Barcode.TYPE_WIFI -> {
                                val ssid = barcode.wifi!!.ssid
                                val password = barcode.wifi!!.password
                                val type = barcode.wifi!!.encryptionType
                            }
                            Barcode.TYPE_URL -> {
                                val title = barcode.url!!.title
                                val url = barcode.url!!.url
                            }
                        }
                    }
                    // [END get_barcodes]
                    // [END_EXCLUDE]
                }
                .addOnFailureListener {
                    // Task failed with an exception
                    // ...
                    Log.e("ERROR..","ERROR")
                }
        // [END run_detector]
    }
}

布局xml文件如上:

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextureView
        android:id="@+id/cameraView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:adjustViewBounds="true" />

    <FrameLayout
        android:id="@+id/framePreview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="gone">

        <ImageView
            android:id="@+id/imagePreview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="centerCrop" />

        <ImageButton
            android:id="@+id/btnRetry"
            android:layout_width="120dp"
            android:layout_height="120dp"
            android:layout_gravity="center"
            android:background="@null"
            android:scaleType="centerCrop"
            android:src="@drawable/ic_refresh" />

    </FrameLayout>

    <LinearLayout 
        android:id="@+id/layout_bottom_sheet"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#FAFAFA"
        android:orientation="vertical"
        app:layout_behavior="@string/bottom_sheet_behavior">

        <ProgressBar
            android:id="@+id/progressBar"
            style="?android:attr/progressBarStyleHorizontal"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:indeterminate="true"
            android:visibility="gone" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:padding="16dp"
            android:text="Detected Barcodes"
            android:textSize="24sp" />

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/rvQrCode"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:paddingLeft="8dp"
            android:paddingRight="8dp" />

    </LinearLayout>

    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/fab_take_photo"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="16dp"
        android:src="@drawable/ic_camera"
        app:backgroundTint="@color/colorPrimary"
        app:fabSize="normal"
        app:layout_anchor="@id/layout_bottom_sheet"
        app:layout_anchorGravity="end"
        app:rippleColor="@color/colorAccent" />

</androidx.coordinatorlayout.widget.CoordinatorLayout>

我的应用成绩文件是这样的:

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.google.firebase.codelab.barcode_scanning"
        minSdkVersion 21
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

androidExtensions {
    experimental = true
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation 'androidx.appcompat:appcompat:1.0.0-rc02'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    testImplementation 'junit:junit:4.13'
    androidTestImplementation 'androidx.test:runner:1.3.0-rc01'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0-rc01'
    implementation 'com.otaliastudios:cameraview:1.6.0'
    implementation "com.google.android.material:material:1.3.0-alpha01"
    implementation "androidx.cardview:cardview:1.0.0"
    // Barcode model
    implementation 'com.google.mlkit:barcode-scanning:16.0.1'
    implementation 'androidx.camera:camera-core:1.0.0-alpha06'
    implementation 'androidx.camera:camera-camera2:1.0.0-alpha06'
}

提前感谢任何人都可以给我的任何帮助。

4

1 回答 1

3

因此,如果我们查看代码:

  1. 从 ImageProxy 创建 InputImage
  2. scanner.process(image).addWhateverListener(etc etc) 但不是 onComplete
  3. imageProxy.close

为什么这行不通?第 2 步是异步的,因此在执行之前需要一小部分时间,但与此同时,第 3 步会启动并清除图像 - 没有要检测的图像。解决方法是使用addOnCompleteListener关闭图像:

    scanner.process(image)
        .addOnFailureListener { // Some code}
        .addOnSuccessListener { // Some more code}
        .addOnCompleteListener {
            // Close the image
            imageProxy.close()}

顺便说一句,这也是我第一次遇到的问题,我们正在考虑添加比“图像已经关闭”更好的调试消息。

于 2020-07-21T20:13:29.003 回答