
출처 : https://genesis-world.readthedocs.io/en/latest/user_guide/getting_started/visualization.html
Genesis에서 제공하는 User Guide를 읽으며 해석하며 어떻게 동작하는지 살펴보겠습니다.
Genesis의 시각화 시스템은 생성한 장면(scene)의 시각화 도구(scene.visualizer)를 통해 관리됩니다. 시각화에는 두 가지 방법이 있습니다:
1. 인터랙티브 뷰어(Interactive Viewer): 별도의 쓰레드에서 실행되어 실시간으로 장면을 보여줍니다.
2. 카메라를 수동으로 추가: 장면에 카메라를 추가하고 이를 사용하여 이미지를 렌더링(rendering)합니다.
뷰어(Viewer)는 Genesis가 제공하는 실시간 시각화 도구입니다.
이 도구를 사용하면 화면에 현재 장면을 실시간으로 렌더링하여 보여줍니다. 특히 개발자나 연구자는 장면의 구성 및 객체의 배치를 직관적으로 확인할 수 있습니다.
뷰어는 장면을 생성할 때 viewer_options와 vis_options 매개변수를 통해 설정할 수 있습니다.
scene = gs.Scene(
show_viewer = True, # 뷰어를 활성화할지 여부
viewer_options = gs.options.ViewerOptions(
res = (1280, 960), # 뷰어 해상도 (픽셀 단위)
camera_pos = (3.5, 0.0, 2.5), # 카메라 위치 (x, y, z 좌표, 단위: 미터)
camera_lookat = (0.0, 0.0, 0.5), # 카메라가 바라볼 점 (x, y, z 좌표)
camera_fov = 40, # 카메라 시야각(Field of View), 단위: 도(degree)
max_FPS = 60, # 최대 초당 프레임 (None으로 설정하면 최대 속도로 실행)
),
vis_options = gs.options.VisOptions(
show_world_frame = True, # 월드 좌표축 시각화 여부
world_frame_size = 1.0, # 월드 좌표축 길이 (단위: 미터)
show_link_frame = False, # 개별 객체 링크의 좌표축 시각화 여부
show_cameras = False, # 추가한 카메라의 메쉬와 시야각 시각화 여부
plane_reflection = True, # 평면 반사 효과 활성화 여부
ambient_light = (0.1, 0.1, 0.1), # 주변광(ambient light) 설정
),
renderer = gs.renderers.Rasterizer(), # 카메라 렌더링 방식 (래스터라이저 사용)
)
res: 뷰어 창의 해상도를 지정합니다. (가로, 세로) 형태의 튜플로 입력하며, 단위를 픽셀로 나타냅니다. (일반적인 해상도를 생각하면 됩니다. 1920x1080, 1280x960 등)None으로 설정하면, Genesis는 디스플레이 높이의 절반 크기로 4:3 비율의 창을 자동 생성합니다.camera_pos: 카메라의 초기 위치를 (x, y, z) 형식으로 지정합니다.camera_lookat: 카메라가 바라볼 지점의 좌표를 설정합니다.camera_fov: 카메라의 시야각(Field of View)을 설정합니다. 값이 작을수록 줌(zoom)이 강해지고, 값이 클수록 넓은 시야를 보여줍니다.max_FPS: 초당 최대 프레임을 설정합니다. None으로 설정하면 최대한 빠르게 실행됩니다.show_world_frame: 월드 좌표축을 화면에 표시합니다. 디버깅이나 위치 파악에 유용합니다.world_frame_size: 월드 좌표축의 길이를 설정합니다.show_link_frame: 객체의 링크 좌표축 표시 여부입니다.show_cameras: 추가된 카메라의 메쉬와 시야각을 시각화할지 여부입니다.plane_reflection: 평면 반사 효과를 활성화합니다.ambient_light: 주변광 설정으로, 장면의 기본적인 밝기를 제어합니다.Genesis는 두 가지 렌더링 백엔드를 지원합니다:
1. Rasterizer: 빠른 렌더링 속도를 제공하며 뷰어와 기본 카메라에서 사용됩니다.
gs.renderers.Rasterizer()gs.renderers.RayTracer()뷰어 객체는 생성된 장면에서 접근할 수 있습니다.
scene.visualizer.viewer 또는 scene.viewer로 뷰어에 접근 가능합니다.cam_pose = scene.viewer.camera_pose cam_pose는 카메라의 현재 위치와 회전 정보를 제공합니다.scene.viewer.set_camera_pose(cam_pose)set_camera_pose() 메서드를 사용하여 카메라의 위치와 방향을 변경할 수 있습니다.카메라는 뷰어나 디스플레이에 연결되지 않으며, 필요할 때만 렌더링된 이미지를 반환합니다. 따라서 카메라는 헤드리스 모드(headless mode)로 작동합니다.
cam = scene.add_camera(
res = (1280, 960), # 렌더링 해상도 (가로 1280, 세로 960)
pos = (3.5, 0.0, 2.5), # 카메라 위치 (x=3.5, y=0.0, z=2.5)
lookat = (0, 0, 0.5), # 카메라가 바라보는 지점
fov = 30, # 시야각(Field of View): 30도
GUI = False # GUI 창을 생성하지 않음
)add_camera: 카메라를 추가하는 Genesis 메서드. res: 렌더링된 이미지의 해상도. 더 높은 해상도는 세부 정보를 많이 보여주지만 처리 속도가 느려질 수 있습니다. pos: 카메라의 위치를 나타내는 (x, y, z) 좌표입니다. lookat: 카메라가 집중해서 바라보는 지점을 지정합니다. fov: 카메라의 시야각으로, 장면을 얼마나 넓게 볼 수 있을지를 결정합니다. GUI: True일 경우 OpenCV 창에 렌더링된 이미지를 실시간으로 보여줍니다.
GUI=True로 설정하면 각 카메라가 OpenCV 창을 생성하여 렌더링된 이미지를 실시간으로 표시합니다.
- GUI를 활성화하면 카메라 렌더링 결과를 실시간으로 확인할 수 있어 디버깅에 유용합니다.
- Viewer GUI와 별도로 작동하므로 혼동하지 않도록 주의해야 합니다.
scene.build(): 장면의 모든 객체와 카메라 설정을 확정하고 렌더링 준비를 마칩니다. 카메라는 RGB 이미지, 깊이 정보(depth), 세그멘테이션 마스크, 표면 법선(surface normals) 렌더링을 지원합니다.
- 설명:
- RGB Image: 카메라가 실제로 볼 수 있는 컬러 이미지입니다.
- Depth: 각 픽셀이 카메라로부터 얼마나 먼지에 대한 거리 정보를 제공합니다.
- Segmentation Mask: 장면 내에서 객체별로 구분된 마스크 이미지를 생성합니다.
- Surface Normals: 각 표면의 방향을 나타내는 법선 벡터 정보를 시각화합니다.
- 기본적으로 RGB만 렌더링되며, 추가 정보를 얻으려면 아래처럼 설정해야 합니다.
기본적으로는 RGB만 렌더링되며, 추가 모드를 활성화하려면 camera.render() 호출 시 매개변수를 설정해야 합니다.
scene.build() # 장면 빌드
# RGB, 깊이 정보, 세그멘테이션 마스크, 표면 법선 렌더링
rgb, depth, segmentation, normal = cam.render(depth=True, segmentation=True, normal=True)
depth=True: 깊이 정보 렌더링 활성화. segmentation=True: 세그멘테이션 마스크 활성화. normal=True: 표면 법선 렌더링 활성화.GUI=True로 설정하고 디스플레이가 연결되어 있다면, 4개의 창(RGB, Depth, Segmentation, Normal)이 표시됩니다.
cv2.waitKey(1)을 추가하거나 render()를 다시 호출하여 새로 고침하면 해결될 수 있습니다.Genesis 카메라는 Viewer와 별도로 동작하며, 필요할 때만 이미지를 렌더링합니다.
# 카메라 녹화를 시작합니다. 녹화가 시작되면 렌더링된 모든 RGB 이미지가 내부적으로 기록됩니다.
'''
이 기능은 카메라가 생성하는 RGB 이미지 데이터를 실시간으로 캡처하고 저장하는 역할을 합니다.
예를 들어, 시뮬레이션에서 특정 장면의 모든 프레임을 기록하거나 후속 분석을 위해 데이터를 저장하는 데 유용합니다.
내부적으로 기록된 데이터는 나중에 추출하거나 시각화, 분석 등에 활용할 수 있습니다.
'''
cam.start_recording()
import numpy as np
for i in range(120):
scene.step()
# change camera position
cam.set_pose(
pos = (3.0 * np.sin(i / 60), 3.0 * np.cos(i / 60), 2.5),
lookat = (0, 0, 0.5),
)
cam.render()
# 녹화를 중지하고 비디오를 저장합니다. filename이 지정되지 않으면 호출한 파일 이름을 사용하여 자동으로 이름이 생성됩니다.
cam.stop_recording(save_to_filename='video.mp4', fps=60)
'''
이 기능은 현재 진행 중인 녹화를 종료하고, 녹화된 내용을 하나의 비디오 파일로 저장합니다.
저장되는 파일 이름은 사용자가 직접 설정할 수 있습니다.
'''
import genesis as gs
gs.init(backend=gs.gpu) # gpu로 변경, cpu는 너무 오래걸리기도 하고...
scene = gs.Scene(
show_viewer = True,
viewer_options = gs.options.ViewerOptions(
res = (1280, 960),
camera_pos = (3.5, 0.0, 2.5),
camera_lookat = (0.0, 0.0, 0.5),
camera_fov = 40,
max_FPS = 60,
),
vis_options = gs.options.VisOptions(
show_world_frame = True,
world_frame_size = 1.0,
show_link_frame = False,
show_cameras = False,
plane_reflection = True,
ambient_light = (0.1, 0.1, 0.1),
),
renderer=gs.renderers.Rasterizer(),
)
plane = scene.add_entity(
gs.morphs.Plane(),
)
franka = scene.add_entity(
gs.morphs.MJCF(file='xml/franka_emika_panda/panda.xml'), # 로봇팔을 불러옵니다.
)
cam = scene.add_camera(
res = (640, 480),
pos = (3.5, 0.0, 2.5),
lookat = (0, 0, 0.5),
fov = 30,
GUI = False,
)
scene.build()
# render rgb, depth, segmentation, and normal
# rgb, depth, segmentation, normal = cam.render(rgb=True, depth=True, segmentation=True, normal=True)
cam.start_recording()
import numpy as np
for i in range(120):
scene.step()
cam.set_pose(
pos = (3.0 * np.sin(i / 60), 3.0 * np.cos(i / 60), 2.5),
lookat = (0, 0, 0.5),
)
cam.render()
cam.stop_recording(save_to_filename='video_franka.mp4', fps=60)

비디오가 저장된 것을 확인할 수 있습니다.

이렇게 path를 지정해주면 지정된 path에 동영상이 생기는 것 또한 확인이 가능합니다.

(결과는 이렇게 저장이 됩니다.)