File size: 4,233 Bytes
7b95dc2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
import copy

import numpy as np


def center_normalize(pcl):
    # Center the point cloud
    centroid = np.mean(pcl, axis=0)
    pcl_centered = pcl - centroid

    # Scale
    max_dist = np.max(pcl_centered)
    pcl_normalized = pcl_centered / (2 * max_dist)

    # Move down till one the lowest point is on z=-0.5
    pcl_normalized[:, 2] += -0.5 - np.min(pcl_normalized[:, 2])

    return pcl_normalized.astype(np.float32)


try:
    import pyrender
    import trimesh
except ImportError:  # Mitsuba-only 脚本只需 center_normalize,可不装 pyrender
    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]]


# code from https://github.com/nv-nguyen/cnos/blob/main/src/poses/pyrender.py

class Render(object):

    def __init__(self, light_intensity):
        if pyrender is None:
            raise ImportError("Render 类需要安装 pyrender、trimesh:pip install pyrender trimesh")

        # camera pose is fixed as np.eye(4)
        cam_pose = np.eye(4)
        # convert openCV camera
        cam_pose[1, 1] = -1
        cam_pose[2, 2] = -1

        self.cam_pose = cam_pose

        # create scene config
        self.ambient_light = np.array(
            [0.3, 0.3, 0.3, 0.3])  # np.array([0.2, 0.2, 0.2])  # np.array([1.0, 1.0, 1.0, 1.0])

        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)

        # create camera and render engine
        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)
            # img = Image.fromarray(np.uint8(rgb))
            # img.save(output_dir + f"_{idx_frame:06d}.png")

            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