📷 相机(Camera)#
系统相机#
当您使用渲染器功能时,MotrixSim 会自动创建一个系统相机。 系统相机可以接受用户的鼠标操作,实现移动、缩放等等。
系统相机操作效果
操作说明:
鼠标左键按下并拖动:绕着焦点旋转摄像头
鼠标右键按下并拖动:移动焦点(此时显示红圈为焦点)
鼠标滚轮:缩放(到焦点位置不可再放大)
系统相机支持mjcf/visual/global中的部分配置,例如:
orthographic: 是否采用正交投影
fovy: 相机视野
azimuth: 初始化下,系统相机绕 z 轴的方位角
elevation: 初始化下,系统相机的俯仰角
场景相机#
除了系统相机之外,您可以在 MJCF 文件中配置额外的 Camera 标签。 我们把这种相机称为场景相机。场景相机可以为可视化提供额外的视角
自定义额外相机#
以go1.xml为例,我们在 mjcf 中定义通过如下方式定义了相机:
<body name="trunk" pos="0 0 0.445" childclass="go1">
<camera name="track" pos="0.846 -1.3 0.316" xyaxes="0.866 0.500 0.000 -0.171 0.296 0.940" mode="track"/>
<camera name="top" pos="-1 0 1" xyaxes="0 -1 0 0.7 0 0.7" mode="track"/>
<camera name="side" pos="0 -2 1" xyaxes="1 0 0 0 1 2" mode="track"/>
<camera name="back" pos="-2.4 0 0.8" target="trunk" mode="targetbody"/>
</body>
这意味着我们在 go1 的 trunk 上定义了 4 个额外的相机。 相机的位置和朝向由 pos 和 xyaxes 指定,mode 指定了相机的运动模式。
切换场景主相机#
默认情况下,MotrixSim 使用系统相机作为主相机。 如果您想使用场景相机作为主相机,可以在 Python API 中通过如下方式切换:
cameras = model.cameras # 获取所有相机(注意这里不包括系统相机)
preview_cameras = [None,*cameras] # None表示系统相机
通过键盘事件切换相机:
if render.input.is_key_just_pressed("right"):
# change to next camera
preview_camera_idx = (preview_camera_idx + 1) % len(preview_cameras)
render.set_main_camera(preview_cameras[preview_camera_idx])
if render.input.is_key_just_pressed("left"):
# change to previous camera
preview_camera_idx = (preview_camera_idx + len(preview_cameras) - 1) % len(preview_cameras)
render.set_main_camera(preview_cameras[preview_camera_idx])
通过左右按键切换场景主相机
RGBD 传感器#
MotrixSim 支持将场景相机转变为 RGBD 视觉传感器,从而允许您获取相机的 RGB 图像和深度图像。 您可以通过以下接口来让一个场景相机渲染到一个离线图片上:
cameras = model.cameras
cameras[0].set_render_target("image", 320, 240) # let this camera render to a image with 320x240 resolution
默认情况下,相机采用 RGB 渲染模式。 如果您想让相机只渲染深度图像,可以设置相机的 depth_only 属性为 True:
cameras[1].set_render_target("image", 640, 480)
cameras[1].depth_only = True # This is a depth only camera
cameras[1].set_near_far(0.1, 1) # Set the near and far plane of the camera
备注
深度图里保存的数值是NDC(normalized device coordinates)空间的。 如果您想将其转换为实际3D空间中与摄像机的距离,可以使用如下公式:
view_z = camera.near_plane / depth
RGBD 相机的实时效果会在左侧的 Camera 面板中显示:
左侧面板展示RGB相机和深度相机实时效果
读取相机图像数据#
要读取相机图像数据,您需要从 RenderApp 上获取 RenderCamera 对象,然后执行 capture 操作。
# press space to capture the rcamera.
if render.input.is_key_just_pressed("space"):
rcam = render.get_camera(0) # get render camera from index
capture_tasks.append((capture_index, rcam.capture()))
capture_index += 1
render.sync(data)
while len(capture_tasks) > 0:
task: CaptureTask
idx, task = capture_tasks[0]
if task.state != "pending":
capture_tasks.popleft()
img = task.take_image()
if img is not None:
import os
os.makedirs("shot", exist_ok=True)
img.save_to_disk(f"shot/capture_{idx}.png")
else:
break
注意到,我们的 capture 操作是异步的,因此RenderCamera.capture方法会返回一个 CaptureTask 对象,您需要保存这个 CaptureTask 对象,并持续去检查它的状态,直到它完成。完成后,您可以通过 task.take_image()方法获取图像数据。
您可以看 Api 文档来获取更多细节: