我一直在遵循这些指南:在 Android 上使用 ML Kit 扫描条形码和图像分析以实现简单的条形码扫描仪。这是我到目前为止所得到的:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
registerForActivityResult(ActivityResultContracts.RequestPermission()) { permission ->
Log.d("-- CAMERA PERMISSION --", permission.toString())
}.launch(Manifest.permission.CAMERA)
val options = BarcodeScannerOptions.Builder()
.setBarcodeFormats(Barcode.FORMAT_EAN_13, Barcode.FORMAT_EAN_8, Barcode.FORMAT_QR_CODE)
.build()
val scanner = BarcodeScanning.getClient(options)
val analyzer = ImageAnalysis.Builder().build().apply {
setAnalyzer(Executors.newSingleThreadExecutor()) {
@OptIn(ExperimentalGetImage::class)
val mediaImage = it.image
if (mediaImage != null) {
val image = InputImage.fromMediaImage(mediaImage, it.imageInfo.rotationDegrees)
val result = scanner.process(image)
.addOnSuccessListener { barcodes ->
for (barcode in barcodes) {
Log.d("Barcode Scanner:", barcode.toString())
}
}
.addOnFailureListener { e ->
e.printStackTrace()
}
}
}
}
setContent {
MyShopTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
CameraPreview(analyzer)
}
}
}
}
}
@Composable
fun CameraPreview(analyzer: ImageAnalysis) {
val lifecycleOwner = LocalLifecycleOwner.current
AndroidView(factory = { context ->
val previewView = PreviewView(context).apply {
scaleType = PreviewView.ScaleType.FILL_CENTER
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
implementationMode = PreviewView.ImplementationMode.COMPATIBLE
}
ProcessCameraProvider.getInstance(context).apply {
addListener({
val cameraProvider = this.get()
val preview = androidx.camera.core.Preview.Builder().build().apply {
setSurfaceProvider(previewView.surfaceProvider)
}
try {
cameraProvider.unbindAll()
cameraProvider.bindToLifecycle(
lifecycleOwner,
CameraSelector.DEFAULT_BACK_CAMERA,
analyzer,
preview
)
} catch (e: Exception) {
e.printStackTrace()
}
}, ContextCompat.getMainExecutor(context))
}
previewView
})
}
有效的是我可以在显示屏上看到相机预览。当我将相机指向条形码时,我希望看到连续的输出:
条码扫描器:
但我什么也没得到。似乎图像分析从未被触发。我的预期是错误的吗?我是否需要以某种方式手动触发图像分析?还是我的代码有问题?
更新: 图像分析似乎只在应用程序启动时运行一次。未检测到条形码,因为相机没有时间捕获条形码的图像。因此,没有输出。
上面链接的文档让我相信,相机会持续向分析仪提供图像:
操作模式
当应用程序的分析管道无法跟上CameraX的分析管道时 帧速率要求,CameraX 可以配置为丢帧 以下方法之一:
非阻塞(默认):在此模式下,执行器始终缓存 将最新图像放入图像缓冲区(类似于深度为 一)当应用程序分析先前的图像时。如果相机X 在应用程序完成处理之前接收到新图像, 新图像保存到同一缓冲区,覆盖前一个图像。
那么为什么图像分析器只考虑一张图像呢?如何让它连续分析来自相机的图像?
SudoKoach 的评论成功了:
val analyzer = ImageAnalysis.Builder().build().apply {
setAnalyzer(Executors.newSingleThreadExecutor()) { imageProxy ->
@OptIn(ExperimentalGetImage::class)
val mediaImage = imageProxy.image
if (mediaImage != null) {
val image = InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees)
val result = scanner.process(image)
.addOnSuccessListener { barcodes ->
for (barcode in barcodes) {
Log.d("Barcode Scanner:", barcode.toString())
}
}
.addOnFailureListener { e ->
e.printStackTrace()
}
.addOnCompleteListener {
imageProxy.close()
}
}
}
}
代码示例下方的文档中确实有一个注释,我错过了。