Kotlin开发相机应用运行时切换不同ML模型的实现问题咨询
实现方案
1. 抽取公共复用变量,消除冗余代码
将你重复编写的预览、相机选择器、相机管理实例抽为Activity全局成员变量,仅在第一次初始化相机时创建,后续切换模型全程复用:
// 新增全局成员变量 private lateinit var cameraProvider: ProcessCameraProvider private lateinit var preview: Preview private lateinit var cameraSelector: CameraSelector // 新增模式管理枚举 private enum class CameraMode { NONE, OBJECT_DETECTION, SCENE_RECOGNITION, CURRENCY_DETECTION, OBSTACLE_DETECTION, HUMAN_HUMAN_INTERACTION } private var currentMode: CameraMode = CameraMode.NONE
修改权限获批后的初始化逻辑,仅在这里创建一次公共实例:
override fun onPermissionsGranted(requestCode: Int, perms: List<String>) { cameraProviderFuture = ProcessCameraProvider.getInstance(this) cameraProviderFuture.addListener({ // 初始化公共复用变量 cameraProvider = cameraProviderFuture.get() preview = Preview.Builder().build() cameraSelector = CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build() preview.setSurfaceProvider(binding.previewView.surfaceProvider) // 默认启动无模型模式 switchCameraMode(CameraMode.NONE) }, ContextCompat.getMainExecutor(this)) // 其余原有逻辑保持不变 }
2. 编写统一的模式切换方法
所有模型切换都通过这个统一方法处理,自动解绑旧用例、绑定新用例:
private fun switchCameraMode(targetMode: CameraMode) { // 先解绑所有已绑定的用例 cameraProvider.unbindAll() currentMode = targetMode when(targetMode) { CameraMode.NONE -> { // 无模型模式仅绑定预览 cameraProvider.bindToLifecycle(this as LifecycleOwner, cameraSelector, preview) } CameraMode.OBJECT_DETECTION -> { // 提前初始化模型(可加判空避免重复加载) if (!::objectDetector.isInitialized) { readyObjectDetectionModel() } // 创建目标检测对应的ImageAnalysis用例 val imageAnalysis = ImageAnalysis.Builder().setTargetResolution(Size(1280, 720)) .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST).build() imageAnalysis.setAnalyzer(ContextCompat.getMainExecutor(this)) { imageProxy -> val rotationDegrees = imageProxy.imageInfo.rotationDegrees val image = imageProxy.image if (image != null) { val processImage = InputImage.fromMediaImage(image, rotationDegrees) objectDetector.process(processImage) .addOnSuccessListener { imageProxy.close() } .addOnFailureListener { imageProxy.close() } } } // 绑定预览+目标检测分析用例 cameraProvider.bindToLifecycle(this as LifecycleOwner, cameraSelector, imageAnalysis, preview) } // 其余4类模型的绑定逻辑按上面的格式补充即可 else -> {} } }
3. 按钮触发逻辑
你已经做好的切换按钮,点击时直接调用切换方法即可,比如目标检测按钮的点击逻辑:
binding.objectDetectionBtn.setOnClickListener { switchCameraMode(CameraMode.OBJECT_DETECTION) } // 无模型模式按钮点击逻辑 binding.noModelBtn.setOnClickListener { switchCameraMode(CameraMode.NONE) }
疑问解答
- 能否仅修改已绑定的用例?可以,CameraX的
bindToLifecycle方法会自动替换同生命周期下已绑定的同类型用例,不过主动调用unbindAll再绑定新用例更稳妥,可避免旧用例后台占用资源。 - 要不要做CameraFragment?如果相机逻辑仅在当前页面使用,完全不需要,上述方案足够简洁。如果后续多个页面需要复用相机能力,再抽成独立Fragment即可。
内容的提问来源于stack exchange,提问作者M Tayyab Asghar
相关产品推荐
相关产品推荐

