| import copy |
|
|
| import numpy as np |
|
|
|
|
| def center_normalize(pcl): |
| |
| centroid = np.mean(pcl, axis=0) |
| pcl_centered = pcl - centroid |
|
|
| |
| max_dist = np.max(pcl_centered) |
| pcl_normalized = pcl_centered / (2 * max_dist) |
|
|
| |
| pcl_normalized[:, 2] += -0.5 - np.min(pcl_normalized[:, 2]) |
|
|
| return pcl_normalized.astype(np.float32) |
|
|
|
|
| try: |
| import pyrender |
| import trimesh |
| except ImportError: |
| pyrender = None |
| trimesh = None |
|
|
|
|
| def pretty_color(x, y, z): |
| x += 0.5 |
| y += +0.5 |
| z = z + 0.5 - 0.0125 |
| vec = np.array([x, y, z]) |
| vec = np.clip(vec, 0.001, 1.0) |
| norm = np.sqrt(np.sum(vec ** 2)) |
| vec /= norm |
| return [vec[0], vec[1], vec[2]] |
|
|
|
|
| |
|
|
| class Render(object): |
|
|
| def __init__(self, light_intensity): |
| if pyrender is None: |
| raise ImportError("Render 类需要安装 pyrender、trimesh:pip install pyrender trimesh") |
|
|
| |
| cam_pose = np.eye(4) |
| |
| cam_pose[1, 1] = -1 |
| cam_pose[2, 2] = -1 |
|
|
| self.cam_pose = cam_pose |
|
|
| |
| self.ambient_light = np.array( |
| [0.3, 0.3, 0.3, 0.3]) |
|
|
| self.light = pyrender.SpotLight( |
| color=np.ones(3), |
| intensity=light_intensity, |
| innerConeAngle=np.pi / 2.0, |
| outerConeAngle=np.pi / 2.0, |
| ) |
|
|
| self.render_engine = {} |
|
|
| def render( |
| self, |
| mesh, |
| obj_poses, |
| img_size, |
| intrinsic, |
| dyn_obj_scale=False, |
| factor=1.5, |
| ): |
|
|
| scene = pyrender.Scene( |
| bg_color=np.array([0., 0., 0., 1.0]), ambient_light=self.ambient_light |
| ) |
|
|
| scene.add(self.light, pose=self.cam_pose) |
|
|
| |
| fx, fy, cx, cy = intrinsic[0], intrinsic[4], intrinsic[2], intrinsic[5] |
|
|
| camera = pyrender.IntrinsicsCamera( |
| fx=fx, fy=fy, cx=cx, cy=cy, znear=0.05, zfar=100000 |
| ) |
| scene.add(camera, pose=self.cam_pose) |
|
|
| if not dyn_obj_scale: |
| cad_node = scene.add(mesh, pose=np.eye(4), name="cad") |
|
|
| if (img_size[1], img_size[0]) not in self.render_engine: |
| self.render_engine[(img_size[1], img_size[0])] = pyrender.OffscreenRenderer(img_size[1], img_size[0]) |
|
|
| rgbs, depths, masks = [], [], [] |
|
|
| for idx_frame in range(obj_poses.shape[0]): |
|
|
| if dyn_obj_scale: |
| trans = obj_poses[idx_frame][:3, 3] |
| dist = ((trans ** 2).sum() ** 0.5) * factor |
|
|
| obj_poses[idx_frame][:3, 3] /= dist |
|
|
| scaled_mesh = copy.deepcopy(mesh).apply_scale(1 / dist) |
| pymesh = pyrender.Mesh.from_trimesh(as_mesh(scaled_mesh), smooth=False) |
|
|
| cad_node = scene.add(pymesh, pose=np.eye(4), name="cad") |
|
|
| scene.set_pose(cad_node, obj_poses[idx_frame]) |
|
|
| rgb, depth = self.render_engine[(img_size[1], img_size[0])].render(scene, |
| pyrender.constants.RenderFlags.RGBA) |
| |
| |
|
|
| if dyn_obj_scale: |
| depth *= dist |
| scene.remove_node(cad_node) |
|
|
| mask = depth > 0 |
| masks.append(mask) |
|
|
| rgbs.append(rgb[..., :3]) |
| depths.append(depth) |
|
|
| return rgbs, depths, masks |
|
|
|
|
| def as_mesh(scene_or_mesh): |
| if trimesh is None: |
| raise ImportError("as_mesh 需要 trimesh") |
| if isinstance(scene_or_mesh, trimesh.Scene): |
| result = trimesh.util.concatenate( |
| [ |
| trimesh.Trimesh(vertices=m.vertices, faces=m.faces) |
| for m in scene_or_mesh.geometry.values() |
| ] |
| ) |
| else: |
| result = scene_or_mesh |
| return result |
|
|