相机帧访问示例
警告! 相机帧访问功能被标记为实验性,因为它目前不完全支持所有公共 AR Foundation API,并且由于包和 Snapdragon Spaces 服务端的优化,版本之间的向后兼容性可能会受到影响。 |
这个示例演示了如何获取 RGB 相机帧和内部属性用于图像处理。有关相机帧访问的基本信息及 AR Foundation 的 AR Camera Manager 组件的功能,请参阅 Unity 文档。要使用此功能,需要在 OpenXR 插件设置中启用它,路径为:项目设置 > XR 插件管理 > OpenXR(> Android 标签)。
示例工作原理
将 AR Camera Manager 组件添加到 AR Session Origin > AR Camera 游戏对象中,将启用相机访问子系统。启动时,子系统会从设备中检索有效的传感器配置。如果找到有效的 Y'UV420sp 或 YUY2 传感器配置,子系统将选择该配置作为 CPU 相机图像的提供者。从概念上讲,AR Camera Manager 代表一个单一的相机,不能同时管理多个传感器。
示例场景包含两个面板:
● 一个相机视频面板,显示来自设备相机的最新 CPU 图像,并带有暂停和恢复按钮。
● 一个相机信息面板,列出设备相机的各种属性。
获取 CPU 图像
每当子系统获得新的相机帧时,AR Camera Manager 将触发 frameReceived 事件。订阅此事件可以让其他脚本尽早获取最新的相机帧并对其进行处理。一旦相机帧可用,Camera Manager 的 TryAcquireLatestCpuImage 函数将返回一个 XRCpuImage 对象,这个对象代表来自选定设备相机的单张原始图像。可以使用 XRCpuImage 的 Convert 函数提取该图像的原始像素数据,Convert 函数会返回一个 NativeArray<byte>。Snapdragon Spaces 不支持通过 XRCpuImage.ConvertAsync 进行异步图像转换。
有关如何使用 frameReceived、TryAcquireLatestCpuImage 和 XRCpuImage 的详细信息,请参阅 Unity 文档。
警告! 根据所使用的设备,相机帧访问可能需要几秒钟才能初始化。在子系统成功初始化之前,请不要尝试访问帧。强烈建议使用 AR Foundation API 的 frameReceived 事件,以避免出现错误。 |
以下示例代码在触发 frameReceived 事件时,从 AR Camera Manager 请求 CPU 图像。如果成功,它将直接将 XRCpuImage 的原始像素数据提取到托管的 Texture2D 的 GetRawTextureData<byte> 缓冲区中,并使用 Apply 方法应用纹理缓冲区。最后,它会更新目标 RawImage 中的纹理,使新帧在应用程序的 UI 中可见。
以下是 AR Camera Manager 支持的纹理格式:
● RGB24
● RGBA32
● BGRA32
检索 YUV 平面数据
Snapdragon Spaces 目前支持 Y′UV420sp 和 YUY2 格式。Y′UV420sp 包含一个 Y 缓冲区,后跟交错的 2x2 子采样 U/V 缓冲区。YUY2 包含一个单一的缓冲区,其中交错了 Y 和 U/V 样本,每个样本以 Y-U-Y-V 的形式表示,代表两个水平像素的色度信息,没有垂直子采样。有关 YUV 颜色模型的详细信息,请参阅 YCbCr 维基百科文章中的 YUV 部分。
如果不需要 RGB 转换,可以通过 XRCpuImage 的 GetPlane 方法检索原始 YUV 平面数据。此方法返回一个 XRCpuImage.Plane 对象,可以从中读取平面数据。通过 XRCpuImage.planeCount 可以区分格式,该属性指示表示帧的平面数量。
Y'UV420sp
● Y 平面数据的索引为 0,可以通过 GetPlane(0) 访问。
● UV 平面数据的索引为 1,可以通过 GetPlane(1) 访问。
YUY2
YUYV 平面数据的索引为 0,可以通过 GetPlane(0) 访问。
有关 XRCpuImage.GetPlane 的详细信息,请参阅 Unity 文档。
有关 XRCpuImage.Plane 的详细信息,请参阅 Unity 文档。
以下示例代码在 frameReceived 事件触发时请求来自 AR Camera Manager 的 CPU 图像,如果成功,它会获取 XRCpuImage 的原始平面数据,并根据 YUV 格式应用不同的图像处理算法。
检索传感器/内部信息
摄像头管理器的 TryGetIntrinsics 函数将返回一个 XRCameraIntrinsics 对象,该对象描述了所选传感器的物理特性。有关 XRCameraIntrinsics 的详细信息,请参阅 Unity 文档。(https://docs.unity3d.com/Packages/com.unity.xr.arsubsystems@4.2/api/UnityEngine.XR.ARSubsystems.XRCameraIntrinsics.html)
以下示例代码检索所选传感器的内参,并在应用程序 UI 中显示这些信息。
检索传感器/外部参数
AR Foundation API 不提供传感器的外参,不过,您可以使用以下两种方法来获取传感器的外参:
方法 1:Snapdragon Spaces 输入绑定
Snapdragon Spaces 提供了 ColorCameraPosition 和 ColorCameraRotation 的输入动作。您可以将这些输入动作与 Tracked Pose Driver (Input System) 配合使用,通过将它们绑定到 Position Input 和 Rotation Input 上。将 Tracked Pose Driver (Input System) 组件添加到一个 GameObject 上,该 GameObject 的位姿将与彩色摄像头的外参位姿匹配。
下图展示了如何使用这些输入绑定。
方法二:Snapdragon Spaces 相机姿态提供器
将Space相机姿态提供器组件添加到场景中,并使用 GetPoseFromProvider 函数来获取与 AR 相机管理器最新的 frameReceived 事件相关的相机姿态。这个姿态是相对于 AR 会话坐标系统的。
下面的示例代码演示了如何获取所选传感器的外参并在应用程序的 UI 中显示。
Spaces Camera Pose Provider还可以用作Tracked Pose Driver的姿势提供程序。
提升性能的提示:
相机访问操作可能会消耗较多计算资源,无论是由于图像分辨率较大还是算法的复杂性。
● 使用 XRCpuImage.Convert 转换图像时,提供较小的 outputDimensions 以减少计算量。
● 使用 XRCpuImage.GetPlane 处理图像时,可以考虑对数据缓冲区进行下采样。
Snapdragon Spaces 提供了直接内存访问转换设置,这改变了 XRCpuImage.Convert 读取和写入数据的方式。默认情况下,Snapdragon Spaces 使用 Marshal.Copy 进行帧数据的移动。启用此设置后,Spaces 将使用 NativeArray<byte> 直接表示源和目标缓冲区。可以在 Project Settings > XR Plug-in Management > OpenXR (> Android Tab) > Snapdragon Spaces > Camera Frame Access (Experimental) > Direct Memory Access Conversion 中找到这个设置。启用此设置可能会在某些设备上提高性能,但在其他架构上的表现可能会有所下降。以下是建议启用直接内存访问转换设置的设备表:
设备 | 建议 |
Lenovo ThinkReality A3 | 性能提升,推荐使用 |
Lenovo ThinkReality VRX | 性能不足,不推荐使用 |
Spaces AR C相机管理器配置和 DownsamplingStride 属性在版本 0.21.0 中已被弃用。请改用 XRCpuImage.ConversionParams 设置较小的 outputDimensions,或者使用 XRCpuImage.GetPlane 并设置自定义下采样因子。
检索其他的传感器数据
Spaces AR Camera Manager Config 可以通过 GetActiveCameraCount 方法获取设备中的相机传感器数量。这些信息对于区分双镜头设备和 VR 设备,以及正确处理相机图像可能非常重要。