Knowhow/Vision

Open3d RGB/Depth image rendering 2

침닦는수건 2023. 3. 20. 18:27
반응형

2022.07.01 - [Knowhow] - Open3d RGB/Depth image rendering 에서 기록한 코드와 크게 다른 것은 없으나 intrinsic, camera pose를 미리 알고 있을 때가 아니라, 그저 Open3d visualizer 상에서 손(drag)으로 돌려가며 구도를 잡은 뒤 해당 구도로 이미지를 rendering하고 싶을 때가 많길래 추가 정리한다.

 

다시 말하면, 구체적인 카메라 파라미터는 필요없고 대충 open3d GUI에서 손으로 구도 잡은 뒤, 그 구도의 RGB/Depth를 얻을 때 자주 썼다. 

 

먼저 이 코드는 준비물이 필요한데, 일단 o3d.visualization.draw_geometries()를 이용해 먼저 visualizer를 켠다. 

 

그리고 원하는 구도로 마우스 드래그를 통해 이동/회전시킨 뒤, P 버튼을 누른다.

 

그러면 o3d.visualization.draw_geometries()를 실행한 코드가 있는 위치에 ScreenCamera_xx.json 파일이 생성되는 것을 볼 수 있다. 

 

이 ScreenCamera_xx.json 파일이 현 visualizer가 사용하는 카메라 파라미터를 담고 있는 파일이다. 아래 코드는 이 파일을 읽어 일일이 손으로 드래그하지 않아도 그 구도로 계속해서 렌더링을 해주는 클래스 코드다.

 

import numpy as np
import open3d as o3d

class Renderer():
    def __init__(self):
        self.vis = o3d.visualization.Visualizer()
        self.vis.create_window(visible=False)
        self.opt = self.vis.get_render_option()
        self.opt.background_color = np.asarray([0, 0, 0])
        self.opt.mesh_color_option = o3d.visualization.MeshColorOption.Color

        self.ctr = self.vis.get_view_control()
        print("Field of view (before changing) %.2f" % self.ctr.get_field_of_view())
        self.ctr.set_constant_z_near(0.001)
        self.ctr.set_constant_z_far(10.)

        self.curr_target = None

    def render(self, target, screen_camera_path):
        if self.curr_target is not None:
            self.vis.remove_geometry(self.curr_target)
            self.vis.add_geometry(target)
            self.curr_target = target
        else:
            self.vis.add_geometry(target)
            self.curr_target = target

        parameters = o3d.io.read_pinhole_camera_parameters(screen_camera_path)
        self.ctr.convert_from_pinhole_camera_parameters(parameters)
        self.vis.poll_events()
        self.vis.update_renderer()

        depth_rn = np.asarray(self.vis.capture_depth_float_buffer(True))
        depth_rn = depth_rn.astype(np.float32)

        rgb_rn = np.asarray(self.vis.capture_screen_float_buffer(True))
        rgb_rn = rgb_rn.astype(np.float32)
        return depth_rn, rgb_rn

    def close(self):
        self.vis.clear_geometries()
        self.vis.destroy_window()

코드가 간단해서 별도의 설명은 필요없어보이지만, 약간의 부가 설명을 더하면 target은 open3d visualizer가 다루는 point cloud나 mesh 파일이 되겠다. 경로(path)가 아닌 o3d.geometry 객체로 넣어주어야 한다.

 

screen_camera_path는 앞서 P버튼을 통해 얻은 ScreenCamera_xx.json 파일까지의 경로를 넣어주면 된다. 만약 구도를 바꿔주고 싶다면 미리 많은 구도를 저장해두고 매번 다른 경로를 넣어주면 된다. 

 

주의

open3d 0.17.0 버전에서는 convert_from_pinhole_camera_paramters()가 안 먹는 버그가 있다. (2023.10.27)

반응형