由于图像已关闭,ML Kit条形码处理失败



我正在寻找几天如何使用ML Kit和CameraX读取二维码。输入图像的处理总是返回失败";IllegalStateException:图像已关闭";。我看了不同的论坛,但我找不到我做错了什么。我想我在遵循谷歌文档,但它不起作用。

这就是我在主活动中所做的:

  1. 我创建了一个textureView,它显示了我相机的输入
  2. 我启动相机(在检查了必要的权限后(
  3. 我设置了一个";预览";用例
  4. 我设置了一个";"图像分析";用例
  5. 我设置了一个分析器,该分析器创建一个传递给条形码扫描仪进程的InputImage
  6. 使用用例设置我的生命周期";预览";以及";图像分析">

我正在使用CameraX版本";1.0.0-alpha04";以及";com.google.mlkit:条形码扫描:16.0.3"。

build.gradle

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 30
buildToolsVersion "30.0.2"
defaultConfig {
applicationId "be.lapit.qrcodescanner"
minSdkVersion 21
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
// ML Kit Barcode scanner
implementation 'com.google.mlkit:barcode-scanning:16.0.3'
implementation 'com.google.android.gms:play-services-mlkit-barcode-scanning:16.1.2'
// CameraX
def camerax_version = "1.0.0-alpha04"
// The following line is optional, as the core library is included indirectly by camera-camera2
implementation "androidx.camera:camera-core:${camerax_version}"
implementation "androidx.camera:camera-camera2:${camerax_version}"
// If you want to additionally use the CameraX Lifecycle library
//implementation "androidx.camera:camera-lifecycle:${camerax_version}"
// If you want to additionally use the CameraX View class
//implementation "androidx.camera:camera-view:1.0.0-alpha17"
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
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">
<LinearLayout
android:id="@+id/linearLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">

<ImageView
android:id="@+id/imageView"
android:layout_width="250px"
android:layout_height="250px"
android:layout_marginBottom="48dp"
android:src="@drawable/thumb_up" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Test textview"/>
<TextureView
android:id="@+id/texture_view"
android:layout_width="600px"
android:layout_height="600px" />

</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

主活动.kt

package be.lapit.qrcodescanner
import android.Manifest
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle
import android.util.Log
import android.util.Size
import android.view.TextureView
import android.widget.Button
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.camera.core.*
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.lifecycle.LifecycleOwner
import com.google.android.gms.tasks.OnFailureListener
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 java.time.Instant
import java.time.format.DateTimeFormatter
import kotlin.system.measureTimeMillis

class MainActivity : AppCompatActivity() {
// PLA: Variable needed to check if user has granted camera permission
companion object {
private const val REQUEST_CAMERA_PERMISSION = 10
}
private lateinit var textureView: TextureView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
textureView = findViewById(R.id.texture_view)
// Request camera permissions
if (isCameraPermissionGranted()) {
textureView.post { startCamera() }
} else {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.CAMERA),
REQUEST_CAMERA_PERMISSION
)
}

}
private fun startCamera() {
// -----------------------
// Setup use case Preview
// -----------------------
val previewConfig : PreviewConfig = PreviewConfig.Builder()
// We want to show input from front camera of the device
.setLensFacing(CameraX.LensFacing.FRONT)
.build()
val preview = Preview(previewConfig)
preview.setOnPreviewOutputUpdateListener { previewOutput ->
textureView.setSurfaceTexture(previewOutput.surfaceTexture)
}
// ------------------------------
// Setup use case Image Analysis
// ------------------------------
val imageAnalysisConfig = ImageAnalysisConfig.Builder()
.setTargetResolution(Size(1280, 720))
.setLensFacing(CameraX.LensFacing.FRONT)
.setImageReaderMode(ImageAnalysis.ImageReaderMode.ACQUIRE_LATEST_IMAGE)
.setImageQueueDepth(1)
.build()
val imageAnalysis = ImageAnalysis(imageAnalysisConfig)
// -------------------
// Set image analyzer
// -------------------
imageAnalysis.setAnalyzer { imageProxy: ImageProxy, rotationDegrees: Int ->
Log.i("Status", "In setAnalyzer on " + System.currentTimeMillis())
val mediaImage = imageProxy.image
if (mediaImage != null) {
val image1 = InputImage.fromMediaImage(mediaImage, rotationDegrees)
// --------------------------
// Configure barcode scanner
// --------------------------
val barcodeScannerOptions: BarcodeScannerOptions = BarcodeScannerOptions.Builder()
.setBarcodeFormats(
Barcode.FORMAT_QR_CODE,
Barcode.FORMAT_AZTEC,
Barcode.FORMAT_EAN_13
)
.build()
// Get an instance of BarcodeScanner
val scanner = BarcodeScanning.getClient(barcodeScannerOptions)
scanner.process(image1)
.addOnSuccessListener ({ barcodes ->
// Task completed successfully
Log.i("Status", "In success listener on timestamp " + System.currentTimeMillis())
for (barcode in barcodes) {
Log.i("Barcode", barcode.toString())
}
Toast.makeText(this,"Ik ben hier eindelijk",Toast.LENGTH_LONG).show();
})
.addOnFailureListener(OnFailureListener {
// Process failed
Log.i("Status", "In failure listener on " +  System.currentTimeMillis() + " because: $it")
Log.i("Failure", "$it")
it.printStackTrace()
})
.addOnCompleteListener {
Log.i("Status", "In complete listener on " +  System.currentTimeMillis())
//imageProxy.close()
}
}
}
// Bind
CameraX.bindToLifecycle(this as LifecycleOwner, preview, imageAnalysis)
}

private fun isCameraPermissionGranted(): Boolean {
val selfPermission = ContextCompat.checkSelfPermission(
baseContext,
Manifest.permission.CAMERA
)
return selfPermission == PackageManager.PERMISSION_GRANTED
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
grantResults: IntArray
) {
if (requestCode == REQUEST_CAMERA_PERMISSION) {
if (isCameraPermissionGranted()) {
textureView.post { startCamera() }
} else {
Toast.makeText(this, "Camera permission is required.", Toast.LENGTH_SHORT).show()
finish()
}
}
}
}

日志信息

I/Status: In setAnalyzer on 1602190069609
I/tflite: Initialized TensorFlow Lite runtime.
I/native: barcode_detector_client.cc:238 Not using NNAPI
I/Status: In failure listener on 1602190069612 because: com.google.mlkit.common.MlKitException: Internal error has occurred when executing ML Kit tasks
I/Failure: com.google.mlkit.common.MlKitException: Internal error has occurred when executing ML Kit tasks
W/System.err: com.google.mlkit.common.MlKitException: Internal error has occurred when executing ML Kit tasks
at com.google.mlkit.common.sdkinternal.ModelResource.zza(com.google.mlkit:common@@17.0.0:32)
at com.google.mlkit.common.sdkinternal.zzl.run(com.google.mlkit:common@@17.0.0)
W/System.err:     at com.google.mlkit.common.sdkinternal.zzp.run(com.google.mlkit:common@@17.0.0:3)
at com.google.mlkit.common.sdkinternal.MlKitThreadPool.zzd(com.google.mlkit:common@@17.0.0:24)
at com.google.mlkit.common.sdkinternal.MlKitThreadPool.zza(com.google.mlkit:common@@17.0.0:30)
at com.google.mlkit.common.sdkinternal.zzh.run(com.google.mlkit:common@@17.0.0)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
at java.lang.Thread.run(Thread.java:762)
Caused by: java.lang.IllegalStateException: Image is already closed
at android.media.Image.throwISEIfImageIsInvalid(Image.java:68)
at android.media.ImageReader$SurfaceImage$SurfacePlane.getBuffer(ImageReader.java:803)
at com.google.mlkit.vision.barcode.internal.zzf.zza(com.google.android.gms:play-services-mlkit-barcode-scanning@@16.1.2:72)
at com.google.mlkit.vision.barcode.internal.zzf.zzb(com.google.android.gms:play-services-mlkit-barcode-scanning@@16.1.2:83)
at com.google.mlkit.vision.barcode.internal.zzf.run(com.google.android.gms:play-services-mlkit-barcode-scanning@@16.1.2:143)
at com.google.mlkit.vision.common.internal.MobileVisionBase.zza(com.google.mlkit:vision-common@@16.1.0:23)
at com.google.mlkit.vision.common.internal.zzc.call(com.google.mlkit:vision-common@@16.1.0)
at com.google.mlkit.common.sdkinternal.ModelResource.zza(com.google.mlkit:common@@17.0.0:29)
... 8 more
I/Status: In complete listener on 1602190069614
In failure listener on 1602190069614 because: com.google.mlkit.common.MlKitException: Internal error has occurred when executing ML Kit tasks
I/Failure: com.google.mlkit.common.MlKitException: Internal error has occurred when executing ML Kit tasks
W/System.err: com.google.mlkit.common.MlKitException: Internal error has occurred when executing ML Kit tasks
at com.google.mlkit.common.sdkinternal.ModelResource.zza(com.google.mlkit:common@@17.0.0:32)
at com.google.mlkit.common.sdkinternal.zzl.run(com.google.mlkit:common@@17.0.0)
at com.google.mlkit.common.sdkinternal.zzp.run(com.google.mlkit:common@@17.0.0:3)
at com.google.mlkit.common.sdkinternal.MlKitThreadPool.zzd(com.google.mlkit:common@@17.0.0:24)
at com.google.mlkit.common.sdkinternal.MlKitThreadPool.zza(com.google.mlkit:common@@17.0.0:30)
at com.google.mlkit.common.sdkinternal.zzh.run(com.google.mlkit:common@@17.0.0)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
at java.lang.Thread.run(Thread.java:762)
W/System.err: Caused by: java.lang.IllegalStateException: Image is already closed
at android.media.Image.throwISEIfImageIsInvalid(Image.java:68)
at android.media.ImageReader$SurfaceImage$SurfacePlane.getBuffer(ImageReader.java:803)
at com.google.mlkit.vision.barcode.internal.zzf.zza(com.google.android.gms:play-services-mlkit-barcode-scanning@@16.1.2:72)
at com.google.mlkit.vision.barcode.internal.zzf.zzb(com.google.android.gms:play-services-mlkit-barcode-scanning@@16.1.2:83)
at com.google.mlkit.vision.barcode.internal.zzf.run(com.google.android.gms:play-services-mlkit-barcode-scanning@@16.1.2:143)
at com.google.mlkit.vision.common.internal.MobileVisionBase.zza(com.google.mlkit:vision-common@@16.1.0:23)
at com.google.mlkit.vision.common.internal.zzc.call(com.google.mlkit:vision-common@@16.1.0)
at com.google.mlkit.common.sdkinternal.ModelResource.zza(com.google.mlkit:common@@17.0.0:29)
... 8 more
I/Status: In complete listener on 1602190069615

为了帮助其他人,我在这里发布了我最新的(工作(代码

构建渐变

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 30
buildToolsVersion "30.0.2"
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
defaultConfig {
applicationId "be.lapit.qrcodescanner"
minSdkVersion 21
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
// ML Kit Barcode scanner
implementation 'com.google.mlkit:barcode-scanning:16.0.3'
implementation 'com.google.android.gms:play-services-mlkit-barcode-scanning:16.1.2'
// CameraX
def camerax_version = "1.0.0-alpha10"
// The following line is optional, as the core library is included indirectly by camera-camera2
implementation "androidx.camera:camera-core:${camerax_version}"
implementation "androidx.camera:camera-camera2:${camerax_version}"
// If you want to additionally use the CameraX Lifecycle library
implementation "androidx.camera:camera-lifecycle:${camerax_version}"
// If you want to additionally use the CameraX View class
implementation "androidx.camera:camera-view:1.0.0-alpha17"
// If you want to additionally use the CameraX Extensions library
implementation "androidx.camera:camera-extensions:1.0.0-alpha17"
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
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">
<LinearLayout
android:id="@+id/linearLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">

<Button
android:id="@+id/btnGallery"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Get picture"></Button>
<FrameLayout
android:id="@+id/container"
android:layout_width="450px"
android:layout_height="450px">
<androidx.camera.view.PreviewView
android:id="@+id/preview_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorRed"
android:layout_gravity="center" />
</FrameLayout>

</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

主活动.kt

package be.lapit.qrcodescanner
import android.Manifest
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle
import android.util.Log
import android.util.Size
import android.view.TextureView
import android.widget.Button
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.camera.core.*
import androidx.camera.core.impl.ImageAnalysisConfig
import androidx.camera.core.impl.PreviewConfig
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.view.PreviewView
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.lifecycle.LifecycleOwner
import com.google.android.gms.tasks.OnFailureListener
import com.google.common.util.concurrent.ListenableFuture
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 java.time.Instant
import java.time.format.DateTimeFormatter
import kotlin.system.measureTimeMillis

class MainActivity : AppCompatActivity() {
// PLA: Variable needed to check if user has granted camera permission
companion object {
private const val REQUEST_CAMERA_PERMISSION = 10
}
private lateinit var cameraProviderFuture : ListenableFuture<ProcessCameraProvider>
private lateinit var previewView: PreviewView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
previewView = findViewById(R.id.preview_view)
// Request camera permissions
if (isCameraPermissionGranted()) {
previewView.post { startCamera() }
} else {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.CAMERA),
REQUEST_CAMERA_PERMISSION
)
}

}
private fun startCamera() {
// -----------------------
// Setup use case Preview
// -----------------------
cameraProviderFuture = ProcessCameraProvider.getInstance(this)
cameraProviderFuture.addListener(Runnable {
val cameraProvider = cameraProviderFuture.get()
bindPreview(cameraProvider)
}, ContextCompat.getMainExecutor(this))
}

fun bindPreview(cameraProvider : ProcessCameraProvider) {
var preview : Preview = Preview.Builder()
.build()
var cameraSelector : CameraSelector = CameraSelector.Builder()
.requireLensFacing(CameraSelector.LENS_FACING_FRONT)
.build()
var previewView: PreviewView = findViewById(R.id.preview_view)
preview.setSurfaceProvider(previewView.surfaceProvider)
val imageAnalysis = ImageAnalysis.Builder()
.setTargetResolution(Size(1280, 720))
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
.build()
// Define options for barcode scanner
val options = BarcodeScannerOptions.Builder()
.setBarcodeFormats(
Barcode.FORMAT_QR_CODE,
Barcode.FORMAT_AZTEC)
.build()
imageAnalysis.setAnalyzer(ContextCompat.getMainExecutor(this), ImageAnalysis.Analyzer { imageProxy ->
val rotationDegrees = imageProxy.imageInfo.rotationDegrees
// Initiate barcode scanner
val scanner = BarcodeScanning.getClient(options)
// insert your code here.
@androidx.camera.core.ExperimentalGetImage
val mediaImage = imageProxy.image
@androidx.camera.core.ExperimentalGetImage
if (mediaImage != null) {
val image = InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees)
// Pass image to an ML Kit Vision API
@androidx.camera.core.ExperimentalGetImage
val result = scanner.process(image)
.addOnSuccessListener { barcodes ->
// Task completed successfully
Log.i("Status", "In success listener")
for (barcode in barcodes) {
val bounds = barcode.boundingBox
val corners = barcode.cornerPoints
val rawValue = barcode.rawValue
Log.i("QR code", rawValue.toString())
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
}
}
}
}
.addOnFailureListener {
// Task failed with an exception
Log.i("Status", "In failure listener")
}
.addOnCompleteListener{
// Task failed with an exception
Log.i("Status", "In on complete listener")
imageProxy.close()
}
}
})
cameraProvider.bindToLifecycle(this as LifecycleOwner, cameraSelector, imageAnalysis, preview)
}

private fun isCameraPermissionGranted(): Boolean {
val selfPermission = ContextCompat.checkSelfPermission(
baseContext,
Manifest.permission.CAMERA
)
return selfPermission == PackageManager.PERMISSION_GRANTED
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
grantResults: IntArray
) {
if (requestCode == REQUEST_CAMERA_PERMISSION) {
if (isCameraPermissionGranted()) {
previewView.post { startCamera() }
} else {
Toast.makeText(this, "Camera permission is required.", Toast.LENGTH_SHORT).show()
finish()
}
}
}
}

我不能100%确定这是否相关,但你能尝试将CameraX依赖项更新到最新版本吗?您的版本是1.0.0-alpha04,而最新版本是1.0.0-beta10。https://developer.android.com/jetpack/androidx/releases/camera

对于您正在使用-setImageReaderMode(ImageAnalysis.ImageReaderMode.ACKUIRE_LATEST_IMAGE(的API,我在CameraX开发网站上找不到它了:https://developer.android.com/reference/androidx/camera/core/ImageAnalysis

至于.setImageQueueDepth(1(,它似乎不适用于默认策略:https://developer.android.com/reference/androidx/camera/core/ImageAnalysis.Builder#setImageQueueDepth(int(

另一个小建议是:您目前在每帧中创建一个新的BarcodeDetector,这可能会很慢。在分析器外部创建一次并重用同一个实例可能会更好。

希望其中一些要点有帮助:(

scanner.produce(image(返回Task对象,您需要等待此任务结束后才能离开。否则,图像可以在分析之前关闭:

Task<List<Barcode>> task = scanner.process(image)
Tasks.await(task);

最新更新