Knowhow/Vision

Open3d RGB/Depth image rendering

침닦는수건 2022. 7. 1. 16:08
반응형

3D 데이터의 시각화를 위해서든 3D데이터의 2D 데이터화를 위해서든 공간에 임의의 위치에 카메라를 두고 렌더링을 해야할 때가 있는데, 다른 툴을 쓰자니 진입 장벽이 높고 라이센스 문제도 있어 애를 먹다가 open3d로 간단히 할 수 있는 방법을 찾아 정리한다.

 

3D graphics 툴 대비 퀄리티나 자유도 측면에서 아쉬운 점은 분명히 있겠지만, 그 정도의 수준을 요구하지 않는다면 충분한 방법같다.

 

open3d.visualization.Visualizer()를 이용하는 방법인데 글로 설명하는 것보다 코드로 설명하는 것이 이해도 쉽고 혹 사용하고자 하는 사람에게도 편할 것 같아 하나의 class로 작성한 코드는 다음과 같다.

 

class Renderer():
    def __init__(self, obj, img_h, img_w):
        self.vis = o3d.visualization.Visualizer()
        self.vis.create_window(visible=True, width=img_w, height=img_h)
        self.vis.add_geometry(obj)
        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.w = img_w
        self.h = img_h

    def render(self, cam_param, T_gk):
        intrinsic = o3d.camera.PinholeCameraIntrinsic(self.w, self.h, cam_param['fx'], cam_param['fy'],  cam_param['cx'], cam_param['cy'])

        new_cam_param = o3d.camera.PinholeCameraParameters()
        new_cam_param.intrinsic = intrinsic
        new_cam_param.extrinsic = np.linalg.inv(T_gk)

        self.ctr.convert_from_pinhole_camera_parameters(new_cam_param)
        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()

 

 

필요한 것은 3D 데이터와 그 데이터를 촬영한 가상 카메라의 파라미터들이다.

 

카메라의 파라미터는 총 7개가 필요하다.

1. image width

2. image height

3. focal length x방향, fx

4. focal length y방향, fy

5. principal point x값, cx  (정확히는 후처리를 위해 필요함, 아래 참고)

6. principal point y값, cy  (정확히는 후처리를 위해 필요함, 아래 참고)

7. camera pose 4x4 matrix

  • T_gk : global coord에서 바라본 cam k의 pose 
  • Pg = T_gk * Pk (Pg: global coord point, Pk: cam coord point)

 

위 7개의 값을 설정한 뒤, 사용하면 output으로 렌더링된 depth 이미지와 rgb 이미지를 얻을 수 있다. 

 

*주의*

open3d에서 왜인지 모르겠는데 cx, cy 값 설정은 제대로 안 먹는다. 다시 말하면, cx, cy를 맘대로 넣어봤자 다음 오류가 나면서 결국엔 이미지 resolution의 중앙값으로 변경되어 처리된다. 해결 방법은 못찾았고 회피 방법은 찾았다.

 

[Open3d WARNING] [ViewControl] ConvertFromPinholeCameraParameters() failed because window height and width do not match.

회피 방법은, 일단 cx, cy 값은 각각 (img_w-1)/2 , (img_h-1)/2 와 같이 이미지 resolution 중앙값으로 넣고 사용한다. 그리고 렌더링된 이미지를 타겟으로 하는 cx, cy에 맞도록 warping을 해주는 방식이다.

M = np.float64([[1, 0, 0],[0, 1, 0]])
                
M[0, 2] = target_cx - (img_w - 1) / 2
M[1, 2] = target_cy - (img_h - 1) / 2

warped_depth = cv2.warpAffine(depth_rn, M, (img_w, img_h), flags=cv2.INTER_NEAREST)
warped_rgb = cv2.warpAffine(rgb_rn, M, (img_w, img_h), flags=cv2.INTER_NEAREST)

위와 같이 후처리해주면 동일한 효과를 얻을 수 있다.

 

참고

2023.03.20 - [Knowhow] - Open3d RGB/Depth image rendering 2

반응형

'Knowhow > Vision' 카테고리의 다른 글

COLMAP read bin/txt/ db files in python  (0) 2022.07.13
COLMAP[GUI] multi-camera setting  (0) 2022.07.07
Obj file의 manifold/non-manifold 구분  (0) 2022.06.30
3D mesh voxelization  (0) 2022.06.17
Opencv large FoV image undistortion  (0) 2022.06.16