indoor_augment.py 6.19 KB
Newer Older
liyinhao's avatar
liyinhao committed
1
2
3
4
5
import numpy as np

from mmdet.datasets.registry import PIPELINES


6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
def _rotz(t):
    """Rotate About Z.

    Rotation about the z-axis.

    Args:
        t (float): Angle of rotation.

    Returns:
        rot_mat (ndarray): Matrix of rotation.
    """
    c = np.cos(t)
    s = np.sin(t)
    rot_mat = np.array([[c, -s, 0], [s, c, 0], [0, 0, 1]])
    return rot_mat


@PIPELINES.register_module()
24
class IndoorFlipData(object):
liyinhao's avatar
liyinhao committed
25
    """Indoor Flip Data.
26

27
28
29
30
31
32
    Flip point_cloud and groundtruth boxes.

    Args:
        seed (int): Numpy random seed.
    """

liyinhao's avatar
liyinhao committed
33
34
    def __init__(self):
        pass
35
36

    def __call__(self, results):
liyinhao's avatar
liyinhao committed
37
38
39
        points = results.get('points', None)
        gt_bboxes_3d = results.get('gt_bboxes_3d', None)
        name = 'scannet' if gt_bboxes_3d.shape[1] == 6 else 'sunrgbd'
40
41
        if np.random.random() > 0.5:
            # Flipping along the YZ plane
liyinhao's avatar
liyinhao committed
42
43
            points[:, 0] = -1 * points[:, 0]
            gt_bboxes_3d[:, 0] = -1 * gt_bboxes_3d[:, 0]
44
            if name == 'sunrgbd':
liyinhao's avatar
liyinhao committed
45
46
                gt_bboxes_3d[:, 6] = np.pi - gt_bboxes_3d[:, 6]
            results['gt_boxes'] = gt_bboxes_3d
47
48
49

        if name == 'scannet' and np.random.random() > 0.5:
            # Flipping along the XZ plane
liyinhao's avatar
liyinhao committed
50
51
52
53
            points[:, 1] = -1 * points[:, 1]
            gt_bboxes_3d[:, 1] = -1 * gt_bboxes_3d[:, 1]
            results['gt_bboxes_3d'] = gt_bboxes_3d
        results['points'] = points
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68

        return results

    def __repr__(self):
        repr_str = self.__class__.__name__
        return repr_str


# TODO: merge outdoor indoor transform.
# TODO: try transform noise.
@PIPELINES.register_module()
class IndoorGlobalRotScale(object):
    """Indoor Global Rotate Scale.

    Augment sunrgbd and scannet data with global rotating and scaling.
69
70

    Args:
liyinhao's avatar
liyinhao committed
71
72
73
74
75
76
77
        seed (int): Numpy random seed.
        use_rotate (bool): Whether to use rotate.
        use_color (bool): Whether to use color.
        use_height (bool): Whether to use height.
        rot_range (float): Range of rotation.
        scale_range (float): Range of scale.
        (List[float]): Mean color of the point cloud.
78
79
    """

liyinhao's avatar
liyinhao committed
80
81
82
83
84
    def __init__(self,
                 use_rotate=True,
                 use_color=False,
                 use_scale=True,
                 use_height=True,
liyinhao's avatar
liyinhao committed
85
86
                 rot_range=[-np.pi / 6, np.pi / 6],
                 scale_range=[0.85, 1.15],
87
                 color_mean=[0.5, 0.5, 0.5]):
liyinhao's avatar
liyinhao committed
88
89
90
91
92
93
        self.use_rotate = use_rotate
        self.use_color = use_color
        self.use_scale = use_scale
        self.use_height = use_height
        self.rot_range = rot_range
        self.scale_range = scale_range
94
        self.color_mean = color_mean
liyinhao's avatar
liyinhao committed
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

    def _rotate_aligned_boxes(self, input_boxes, rot_mat):
        """Rotate Aligned Boxes.

        Rotate function for the aligned boxes.

        Args:
            input_boxes (ndarray): 3D boxes.
            rot_mat (ndarray): Rotation matrix.

        Returns:
            rotated_boxes (ndarry): 3D boxes after rotation.
        """
        centers, lengths = input_boxes[:, 0:3], input_boxes[:, 3:6]
        new_centers = np.dot(centers, np.transpose(rot_mat))

        dx, dy = lengths[:, 0] / 2.0, lengths[:, 1] / 2.0
        new_x = np.zeros((dx.shape[0], 4))
        new_y = np.zeros((dx.shape[0], 4))

        for i, crnr in enumerate([(-1, -1), (1, -1), (1, 1), (-1, 1)]):
            crnrs = np.zeros((dx.shape[0], 3))
            crnrs[:, 0] = crnr[0] * dx
            crnrs[:, 1] = crnr[1] * dy
            crnrs = np.dot(crnrs, np.transpose(rot_mat))
            new_x[:, i] = crnrs[:, 0]
            new_y[:, i] = crnrs[:, 1]

        new_dx = 2.0 * np.max(new_x, 1)
        new_dy = 2.0 * np.max(new_y, 1)
        new_lengths = np.stack((new_dx, new_dy, lengths[:, 2]), axis=1)

        return np.concatenate([new_centers, new_lengths], axis=1)
128
129

    def __call__(self, results):
liyinhao's avatar
liyinhao committed
130
131
132
        points = results.get('points', None)
        gt_bboxes_3d = results.get('gt_bboxes_3d', None)
        name = 'scannet' if gt_bboxes_3d.shape[1] == 6 else 'sunrgbd'
liyinhao's avatar
liyinhao committed
133
134

        if self.use_rotate:
liyinhao's avatar
liyinhao committed
135
136
            rot_angle = np.random.random() * (
                self.rot_range[1] - self.rot_range[0]) + self.rot_range[0]
liyinhao's avatar
liyinhao committed
137
            rot_mat = _rotz(rot_angle)
liyinhao's avatar
liyinhao committed
138
            points[:, 0:3] = np.dot(points[:, 0:3], np.transpose(rot_mat))
liyinhao's avatar
liyinhao committed
139
140

            if name == 'scannet':
liyinhao's avatar
liyinhao committed
141
142
                gt_bboxes_3d = self._rotate_aligned_boxes(
                    gt_bboxes_3d, rot_mat)
liyinhao's avatar
liyinhao committed
143
            else:
liyinhao's avatar
liyinhao committed
144
145
146
                gt_bboxes_3d[:, 0:3] = np.dot(gt_bboxes_3d[:, 0:3],
                                              np.transpose(rot_mat))
                gt_bboxes_3d[:, 6] -= rot_angle
liyinhao's avatar
liyinhao committed
147
148
149

        # Augment RGB color
        if self.use_color:
liyinhao's avatar
liyinhao committed
150
151
152
153
154
155
            rgb_color = points[:, 3:6] + self.color_mean
            # brightness change for each channel
            rgb_color *= (1 + 0.4 * np.random.random(3) - 0.2)
            # color shift for each channel
            rgb_color += (0.1 * np.random.random(3) - 0.05)
            # jittering on each pixel
liyinhao's avatar
liyinhao committed
156
            rgb_color += np.expand_dims(
liyinhao's avatar
liyinhao committed
157
                (0.05 * np.random.random(points.shape[0]) - 0.025), -1)
liyinhao's avatar
liyinhao committed
158
159
160
            rgb_color = np.clip(rgb_color, 0, 1)
            # randomly drop out 30% of the points' colors
            rgb_color *= np.expand_dims(
liyinhao's avatar
liyinhao committed
161
162
                np.random.random(points.shape[0]) > 0.3, -1)
            points[:, 3:6] = rgb_color - self.color_mean
liyinhao's avatar
liyinhao committed
163
164

        if self.use_scale:
liyinhao's avatar
liyinhao committed
165
166
167
168
169
170
171
172
            # Augment point cloud scale
            scale_ratio = np.random.random() * (
                self.scale_range[1] -
                self.scale_range[0]) + self.scale_range[0]
            scale_ratio = np.tile(scale_ratio, 3)[None, ...]
            points[:, 0:3] *= scale_ratio
            gt_bboxes_3d[:, 0:3] *= scale_ratio
            gt_bboxes_3d[:, 3:6] *= scale_ratio
liyinhao's avatar
liyinhao committed
173
            if self.use_height:
liyinhao's avatar
liyinhao committed
174
                points[:, -1] *= scale_ratio[0, 0]
liyinhao's avatar
liyinhao committed
175

liyinhao's avatar
liyinhao committed
176
177
        results['points'] = points
        results['gt_bboxes_3d'] = gt_bboxes_3d
178
179
180
181
        return results

    def __repr__(self):
        repr_str = self.__class__.__name__
liyinhao's avatar
liyinhao committed
182
183
184
185
        repr_str += '(use_rotate={})'.format(self.use_rotate)
        repr_str += '(use_color={})'.format(self.use_color)
        repr_str += '(use_scale={})'.format(self.use_scale)
        repr_str += '(use_height={})'.format(self.use_height)
186
        return repr_str