您可以在机器学习管道中使用 ARCore 捕获的摄像头画面打造智能的增强现实体验。 ARCore 机器学习套件示例演示了如何使用机器学习套件和 Google Cloud Vision API 识别真实对象。 此示例使用机器学习模型对摄像头视图中的对象进行分类,并将标签附加到虚拟场景中的对象。
ARCore 机器学习套件示例 用 Kotlin 编写。它还以 ml_kotlin 示例的形式提供 应用(位于 ARCore SDK 中) GitHub 代码库。
使用 ARCore 的 CPU 图像
默认情况下,ARCore 会捕获至少两组图像流:
- 用于特征识别和图像处理的 CPU 图像流。默认情况下,CPU 映像的分辨率为 VGA (640x480)。如果需要,可以将 ARCore 配置为使用其他更高分辨率的图像流。
- 一种 GPU 纹理流,它包含高分辨率纹理,通常分辨率为 1080p。这通常用作面向用户的相机预览。
它存储在
Session.setCameraTextureName()
指定的 OpenGL 纹理中。 SharedCamera.setAppSurfaces()
指定的任何其他视频流。
CPU 映像大小注意事项
如果使用默认 VGA 大小的 CPU 流,则不会产生额外费用,因为 ARCore 使用此流来理解世界。请求具有不同分辨率的流的开销可能会很大,因为需要捕获其他流。请记住,较高的分辨率可能很快就会成为模型开销高昂的问题:将图像的宽度和高度加倍,图像中的像素数就会增加两倍。
如果您的模型仍然可以在较低分辨率图片上表现良好,则缩小图像可能有利。
配置额外的高分辨率 CPU 图像流
机器学习模型的性能可能取决于用作输入的图片的分辨率。您可以通过以下方式调整这些视频流的分辨率:使用 Session.setCameraConfig()
更改当前的 CameraConfig
,并从 Session.getSupportedCameraConfigs()
中选择有效配置。
Java
CameraConfigFilter cameraConfigFilter = new CameraConfigFilter(session) // World-facing cameras only. .setFacingDirection(CameraConfig.FacingDirection.BACK); List<CameraConfig> supportedCameraConfigs = session.getSupportedCameraConfigs(cameraConfigFilter); // Select an acceptable configuration from supportedCameraConfigs. CameraConfig cameraConfig = selectCameraConfig(supportedCameraConfigs); session.setCameraConfig(cameraConfig);
Kotlin
val cameraConfigFilter = CameraConfigFilter(session) // World-facing cameras only. .setFacingDirection(CameraConfig.FacingDirection.BACK) val supportedCameraConfigs = session.getSupportedCameraConfigs(cameraConfigFilter) // Select an acceptable configuration from supportedCameraConfigs. val cameraConfig = selectCameraConfig(supportedCameraConfigs) session.setCameraConfig(cameraConfig)
检索 CPU 映像
使用 Frame.acquireCameraImage()
检索 CPU 映像。
不再需要这些图片时,应立即将其丢弃。
Java
Image cameraImage = null; try { cameraImage = frame.acquireCameraImage(); // Process `cameraImage` using your ML inference model. } catch (NotYetAvailableException e) { // NotYetAvailableException is an exception that can be expected when the camera is not ready // yet. The image may become available on a next frame. } catch (RuntimeException e) { // A different exception occurred, e.g. DeadlineExceededException, ResourceExhaustedException. // Handle this error appropriately. handleAcquireCameraImageFailure(e); } finally { if (cameraImage != null) { cameraImage.close(); } }
Kotlin
// NotYetAvailableException is an exception that can be expected when the camera is not ready yet. // Map it to `null` instead, but continue to propagate other errors. fun Frame.tryAcquireCameraImage() = try { acquireCameraImage() } catch (e: NotYetAvailableException) { null } catch (e: RuntimeException) { // A different exception occurred, e.g. DeadlineExceededException, ResourceExhaustedException. // Handle this error appropriately. handleAcquireCameraImageFailure(e) } // The `use` block ensures the camera image is disposed of after use. frame.tryAcquireCameraImage()?.use { image -> // Process `image` using your ML inference model. }
处理 CPU 映像
为了处理 CPU 映像,可以使用各种机器学习库。
- 机器学习套件:机器学习套件提供设备端对象检测和跟踪 API。
它附带内置于 API 中的粗分类器,还可以使用自定义分类模型来覆盖较窄的对象领域。
使用
InputImage.fromMediaImage
将 CPU 映像转换为InputImage
。 - Firebase 机器学习:Firebase 提供在云端或设备端运行的机器学习 API。 请参阅有关在 Android 上使用 Firebase Auth 和 Firebase Functions 通过 Cloud Vision 安全地为图片加标签的 Firebase 文档。
在 AR 场景中显示结果
图像识别模型通常通过指示代表所检测到的对象的中心点或边界多边形来输出检测到的对象。
使用模型输出的边界框的中心点或中心,可以将锚点附加到检测到的对象。使用 Frame.hitTest()
估算虚拟场景中对象的姿态。
将 IMAGE_PIXELS
坐标转换为 VIEW
坐标:
Java
// Suppose `mlResult` contains an (x, y) of a given point on the CPU image. float[] cpuCoordinates = new float[] {mlResult.getX(), mlResult.getY()}; float[] viewCoordinates = new float[2]; frame.transformCoordinates2d( Coordinates2d.IMAGE_PIXELS, cpuCoordinates, Coordinates2d.VIEW, viewCoordinates); // `viewCoordinates` now contains coordinates suitable for hit testing.
Kotlin
// Suppose `mlResult` contains an (x, y) of a given point on the CPU image. val cpuCoordinates = floatArrayOf(mlResult.x, mlResult.y) val viewCoordinates = FloatArray(2) frame.transformCoordinates2d( Coordinates2d.IMAGE_PIXELS, cpuCoordinates, Coordinates2d.VIEW, viewCoordinates ) // `viewCoordinates` now contains coordinates suitable for hit testing.
使用以下 VIEW
坐标执行点击测试并根据结果创建锚点:
Java
List<HitResult> hits = frame.hitTest(viewCoordinates[0], viewCoordinates[1]); HitResult depthPointResult = null; for (HitResult hit : hits) { if (hit.getTrackable() instanceof DepthPoint) { depthPointResult = hit; break; } } if (depthPointResult != null) { Anchor anchor = depthPointResult.getTrackable().createAnchor(depthPointResult.getHitPose()); // This anchor will be attached to the scene with stable tracking. // It can be used as a position for a virtual object, with a rotation prependicular to the // estimated surface normal. }
Kotlin
val hits = frame.hitTest(viewCoordinates[0], viewCoordinates[1]) val depthPointResult = hits.filter { it.trackable is DepthPoint }.firstOrNull() if (depthPointResult != null) { val anchor = depthPointResult.trackable.createAnchor(depthPointResult.hitPose) // This anchor will be attached to the scene with stable tracking. // It can be used as a position for a virtual object, with a rotation prependicular to the // estimated surface normal. }
性能考虑因素
请遵循以下建议以节省处理能力并降低能耗:
- 不要对每个传入帧运行机器学习模型。请考虑改为以较低的帧速率运行对象检测。
- 考虑使用在线机器学习推理模型来降低计算复杂性。