Beispiel #1
0
    def __init__(self,
                 data_paths,
                 input_transform=None,
                 target_transform=None,
                 data_root='/',
                 explicit_rotation=-1,
                 ignore_label=255,
                 return_transformation=False,
                 augment_data=False,
                 config=None,
                 **kwargs):
        if explicit_rotation > 0:
            raise NotImplementedError

        self.augment_data = augment_data
        self.config = config
        super().__init__(data_paths,
                         input_transform=input_transform,
                         target_transform=target_transform,
                         cache=cache,
                         data_root=data_root,
                         explicit_rotation=explicit_rotation,
                         ignore_mask=ignore_label,
                         return_transformation=return_transformation)

        self.sparse_voxelizer = Voxelizer(
            voxel_size=self.VOXEL_SIZE,
            clip_bound=self.CLIP_BOUND,
            use_augmentation=augment_data,
            scale_augmentation_bound=self.SCALE_AUGMENTATION_BOUND,
            rotation_augmentation_bound=self.ROTATION_AUGMENTATION_BOUND,
            translation_augmentation_ratio_bound=self.
            TRANSLATION_AUGMENTATION_RATIO_BOUND,
            ignore_label=ignore_label)

        # map labels not evaluated to ignore_label
        if self.IGNORE_LABELS is not None:
            label_map = {}
            n_used = 0
            for l in range(self.NUM_LABELS):
                if l in self.IGNORE_LABELS:
                    label_map[l] = self.ignore_mask
                elif l not in self.INSTANCE_LABELS:
                    label_map[l] = n_used
                    n_used += 1
            for l in self.INSTANCE_LABELS:
                label_map[l] = n_used
                n_used += 1
            label_map[self.ignore_mask] = self.ignore_mask
            self.label_map = label_map
            self.NUM_LABELS -= len(self.IGNORE_LABELS)
Beispiel #2
0
    def __init__(self,
                 data_paths,
                 prevoxel_transform=None,
                 input_transform=None,
                 target_transform=None,
                 data_root='/',
                 ignore_label=255,
                 return_transformation=False,
                 augment_data=False,
                 config=None,
                 **kwargs):

        self.augment_data = augment_data
        self.config = config
        VoxelizationDatasetBase.__init__(
            self,
            data_paths,
            prevoxel_transform=prevoxel_transform,
            input_transform=input_transform,
            target_transform=target_transform,
            cache=cache,
            data_root=data_root,
            ignore_mask=ignore_label,
            return_transformation=return_transformation)

        # Prevoxel transformations
        self.voxelizer = Voxelizer(
            voxel_size=self.VOXEL_SIZE,
            clip_bound=self.CLIP_BOUND,
            use_augmentation=augment_data,
            scale_augmentation_bound=self.SCALE_AUGMENTATION_BOUND,
            rotation_augmentation_bound=self.ROTATION_AUGMENTATION_BOUND,
            translation_augmentation_ratio_bound=self.
            TRANSLATION_AUGMENTATION_RATIO_BOUND,
            ignore_label=ignore_label)

        # map labels not evaluated to ignore_label
        label_map = {}
        n_used = 0
        for l in range(self.NUM_LABELS):
            if l in self.IGNORE_LABELS:
                label_map[l] = self.ignore_mask
            else:
                label_map[l] = n_used
                n_used += 1
        label_map[self.ignore_mask] = self.ignore_mask
        self.label_map = label_map
        self.NUM_LABELS -= len(self.IGNORE_LABELS)
Beispiel #3
0
class VoxelizationDataset(VoxelizationDatasetBase):
    """This dataset loads RGB point clouds and their labels as a list of points
  and voxelizes the pointcloud with sufficient data augmentation.
  """
    # Voxelization arguments
    VOXEL_SIZE = 0.05  # 5cm

    # Coordinate Augmentation Arguments: Unlike feature augmentation, coordinate
    # augmentation has to be done before voxelization
    SCALE_AUGMENTATION_BOUND = (0.9, 1.1)
    ROTATION_AUGMENTATION_BOUND = ((-np.pi / 6, np.pi / 6), (-np.pi, np.pi),
                                   (-np.pi / 6, np.pi / 6))
    TRANSLATION_AUGMENTATION_RATIO_BOUND = ((-0.2, 0.2), (-0.05, 0.05), (-0.2,
                                                                         0.2))
    ELASTIC_DISTORT_PARAMS = None

    # MISC.
    PREVOXELIZATION_VOXEL_SIZE = None

    # Augment coords to feats
    AUGMENT_COORDS_TO_FEATS = False

    def __init__(self,
                 data_paths,
                 prevoxel_transform=None,
                 input_transform=None,
                 target_transform=None,
                 data_root='/',
                 ignore_label=255,
                 return_transformation=False,
                 augment_data=False,
                 config=None,
                 **kwargs):

        self.augment_data = augment_data
        self.config = config
        VoxelizationDatasetBase.__init__(
            self,
            data_paths,
            prevoxel_transform=prevoxel_transform,
            input_transform=input_transform,
            target_transform=target_transform,
            cache=cache,
            data_root=data_root,
            ignore_mask=ignore_label,
            return_transformation=return_transformation)

        # Prevoxel transformations
        self.voxelizer = Voxelizer(
            voxel_size=self.VOXEL_SIZE,
            clip_bound=self.CLIP_BOUND,
            use_augmentation=augment_data,
            scale_augmentation_bound=self.SCALE_AUGMENTATION_BOUND,
            rotation_augmentation_bound=self.ROTATION_AUGMENTATION_BOUND,
            translation_augmentation_ratio_bound=self.
            TRANSLATION_AUGMENTATION_RATIO_BOUND,
            ignore_label=ignore_label)

        # map labels not evaluated to ignore_label
        label_map = {}
        n_used = 0
        for l in range(self.NUM_LABELS):
            if l in self.IGNORE_LABELS:
                label_map[l] = self.ignore_mask
            else:
                label_map[l] = n_used
                n_used += 1
        label_map[self.ignore_mask] = self.ignore_mask
        self.label_map = label_map
        self.NUM_LABELS -= len(self.IGNORE_LABELS)

    def _augment_coords_to_feats(self, coords, feats, labels=None):
        norm_coords = coords - coords.mean(0)
        # color must come first.
        if isinstance(coords, np.ndarray):
            feats = np.concatenate((feats, norm_coords), 1)
        else:
            feats = torch.cat((feats, norm_coords), 1)
        return coords, feats, labels

    def convert_mat2cfl(self, mat):
        # Generally, xyz,rgb,label
        return mat[:, :3], mat[:, 3:-1], mat[:, -1]

    def __getitem__(self, index):
        coords, feats, labels, center = self.load_ply(index)
        # Downsample the pointcloud with finer voxel size before transformation for memory and speed
        if self.PREVOXELIZATION_VOXEL_SIZE is not None:
            inds = ME.utils.sparse_quantize(coords /
                                            self.PREVOXELIZATION_VOXEL_SIZE,
                                            return_index=True)
            coords = coords[inds]
            feats = feats[inds]
            labels = labels[inds]

        # Prevoxel transformations
        if self.prevoxel_transform is not None:
            coords, feats, labels = self.prevoxel_transform(
                coords, feats, labels)

        coords, feats, labels, transformation = self.voxelizer.voxelize(
            coords, feats, labels, center=center)

        # map labels not used for evaluation to ignore_label
        if self.input_transform is not None:
            coords, feats, labels = self.input_transform(coords, feats, labels)
        if self.target_transform is not None:
            coords, feats, labels = self.target_transform(
                coords, feats, labels)
        if self.IGNORE_LABELS is not None:
            labels = np.array([self.label_map[x] for x in labels],
                              dtype=np.int)

        # Use coordinate features if config is set
        if self.AUGMENT_COORDS_TO_FEATS:
            coords, feats, labels = self._augment_coords_to_feats(
                coords, feats, labels)

        return_args = [coords, feats, labels]
        if self.return_transformation:
            return_args.append(transformation.astype(np.float32))

        return tuple(return_args)
Beispiel #4
0
def main():
    pcd = o3d.io.read_point_cloud(INPUT_PCD)
    pcd_xyz, pcd_feats = np.asarray(pcd.points), np.asarray(pcd.colors)
    print(f'Finished reading {INPUT_PCD}:')
    print(f'# points: {pcd_xyz.shape[0]} points')
    print(f'volume: {np.prod(pcd_xyz.max(0) - pcd_xyz.min(0))} m^3')

    sparse_voxelizer = Voxelizer(voxel_size=0.05)

    height = pcd_xyz[:, LOCFEAT_IDX].copy()
    height -= np.percentile(height, 0.99)
    pcd_feats = np.hstack((pcd_feats, height[:, None]))

    preprocess = []
    for i in range(7):
        start = time.time()
        coords, feats, labels, transformation = sparse_voxelizer.voxelize(
            pcd_xyz, pcd_feats, None)
        preprocess.append(time.time() - start)
    print('Voxelization time average: ', np.mean(preprocess[2:]))

    coords = ME.utils.batched_coordinates([torch.from_numpy(coords).int()])
    feats = torch.from_numpy(feats.astype(np.float32)).to('cuda')

    config = get_config()
    DatasetClass = load_dataset(config.dataset)
    dataloader = initialize_data_loader(DatasetClass,
                                        config,
                                        threads=config.threads,
                                        phase=config.test_phase,
                                        augment_data=False,
                                        shuffle=False,
                                        repeat=False,
                                        batch_size=config.test_batch_size,
                                        limit_numpoints=False)
    pipeline_model = load_pipeline(config, dataloader.dataset)
    if config.weights.lower() != 'none':
        state = torch.load(config.weights)
        pipeline_model.load_state_dict(
            state['state_dict'], strict=(not config.lenient_weight_loading))

    pipeline_model.eval()

    evaltime = []
    for i in range(7):
        start = time.time()
        sinput = ME.SparseTensor(feats, coords).to('cuda')
        datum = {'sinput': sinput, 'anchor_match_coords': None}
        outputs = pipeline_model(datum, False)
        evaltime.append(time.time() - start)
    print('Network runtime average: ', np.mean(evaltime[2:]))

    pred = outputs['detection'][0]
    pred_mask = pred[:, -1] > MIN_CONF
    pred = pred[pred_mask]
    print(f'Detected {pred.shape[0]} instances')

    bbox_xyz = pred[:, :6]
    bbox_xyz += 0.5
    bbox_xyz[:, :3] += 0.5
    bbox_xyz[:, 3:] -= 0.5
    bbox_xyz[:, 3:] = np.maximum(bbox_xyz[:, 3:], bbox_xyz[:, :3] + 0.1)
    bbox_xyz = bbox_xyz.reshape(-1, 3)
    bbox_xyz1 = np.hstack((bbox_xyz, np.ones((bbox_xyz.shape[0], 1))))
    bbox_xyz = np.linalg.solve(transformation.reshape(4, 4),
                               bbox_xyz1.T).T[:, :3].reshape(-1, 6)
    pred = np.hstack((bbox_xyz, pred[:, 6:]))
    pred_pcd = pc_utils.visualize_bboxes(pred[:, :6],
                                         pred[:, 6],
                                         num_points=1000)

    mesh = o3d.io.read_triangle_mesh(INPUT_MESH)
    mesh.compute_vertex_normals()
    pc_utils.visualize_pcd(mesh, pred_pcd)
Beispiel #5
0
class SparseVoxelizationDataset(VoxelizationDatasetBase):
    """This dataset loads RGB point clouds and their labels as a list of points
  and voxelizes the pointcloud with sufficient data augmentation.
  """

    IS_ROTATION_BBOX = False
    HAS_GT_BBOX = False

    # Voxelization arguments
    VOXEL_SIZE = 0.05  # 5cm

    # Augmentation arguments
    SCALE_AUGMENTATION_BOUND = (0.9, 1.1)
    ROTATION_AUGMENTATION_BOUND = ((-np.pi / 6, np.pi / 6), (-np.pi, np.pi),
                                   (-np.pi / 6, np.pi / 6))
    TRANSLATION_AUGMENTATION_RATIO_BOUND = ((-0.2, 0.2), (-0.05, 0.05), (-0.2,
                                                                         0.2))
    ELASTIC_DISTORT_PARAMS = None

    def __init__(self,
                 data_paths,
                 input_transform=None,
                 target_transform=None,
                 data_root='/',
                 explicit_rotation=-1,
                 ignore_label=255,
                 return_transformation=False,
                 augment_data=False,
                 config=None,
                 **kwargs):
        if explicit_rotation > 0:
            raise NotImplementedError

        self.augment_data = augment_data
        self.config = config
        super().__init__(data_paths,
                         input_transform=input_transform,
                         target_transform=target_transform,
                         cache=cache,
                         data_root=data_root,
                         explicit_rotation=explicit_rotation,
                         ignore_mask=ignore_label,
                         return_transformation=return_transformation)

        self.sparse_voxelizer = Voxelizer(
            voxel_size=self.VOXEL_SIZE,
            clip_bound=self.CLIP_BOUND,
            use_augmentation=augment_data,
            scale_augmentation_bound=self.SCALE_AUGMENTATION_BOUND,
            rotation_augmentation_bound=self.ROTATION_AUGMENTATION_BOUND,
            translation_augmentation_ratio_bound=self.
            TRANSLATION_AUGMENTATION_RATIO_BOUND,
            ignore_label=ignore_label)

        # map labels not evaluated to ignore_label
        if self.IGNORE_LABELS is not None:
            label_map = {}
            n_used = 0
            for l in range(self.NUM_LABELS):
                if l in self.IGNORE_LABELS:
                    label_map[l] = self.ignore_mask
                elif l not in self.INSTANCE_LABELS:
                    label_map[l] = n_used
                    n_used += 1
            for l in self.INSTANCE_LABELS:
                label_map[l] = n_used
                n_used += 1
            label_map[self.ignore_mask] = self.ignore_mask
            self.label_map = label_map
            self.NUM_LABELS -= len(self.IGNORE_LABELS)

    def convert_mat2cfl(self, mat):
        # Generally, xyz, rgb, label
        return mat[:, :3], mat[:, 3:-2], mat[:, -2:]

    def _augment_elastic_distortion(self, pointcloud):
        if self.ELASTIC_DISTORT_PARAMS is not None:
            if random.random() < 0.95:
                for granularity, magnitude in self.ELASTIC_DISTORT_PARAMS:
                    pointcloud = elastic_distortion(pointcloud, granularity,
                                                    magnitude)
        return pointcloud

    def __getitem__(self, index):
        pointcloud, bboxes, center = self.load_datafile(index)
        if self.augment_data and self.config.elastic_distortion:
            pointcloud = self._augment_elastic_distortion(pointcloud)
        coords, feats, labels = self.convert_mat2cfl(pointcloud)
        feats = self._augment_locfeat(coords, feats)
        coords, feats, labels, transformation = self.sparse_voxelizer.voxelize(
            coords, feats, labels, center=center)

        # transform bboxes to match the voxelization transformation.
        # TODO(jgwak): Support rotation augmentation.
        if self.HAS_GT_BBOX:
            bboxes_xyz = np.hstack(
                (bboxes[:, :6].reshape(-1, 3), np.ones(
                    (bboxes.shape[0] * 2, 1))))
            bboxes_xyz = bboxes_xyz @ transformation.reshape(4, 4).T
            bboxes_xyz = (bboxes_xyz[:, :3] / bboxes_xyz[:, 3, None]).reshape(
                -1, 2, 3)
            bboxes_xyz = np.hstack((bboxes_xyz.min(1), bboxes_xyz.max(1)))
            bboxes = np.hstack((bboxes_xyz, bboxes[:, 6:]))

        if labels is None:
            semantic_labels = np.ones(
                coords.shape[0]) * self.config.ignore_label
            instance_labels = np.ones(
                coords.shape[0]) * self.config.ignore_label
        else:
            semantic_labels, instance_labels = labels.T

        # map labels not used for evaluation to ignore_label
        if self.input_transform is not None:
            coords, feats, bboxes = self.input_transform(coords, feats, bboxes)
        if self.target_transform is not None:
            coords, feats, bboxes = self.target_transform(
                coords, feats, bboxes)
        if self.IGNORE_LABELS is not None:
            semantic_labels = np.array(
                [self.label_map[x] for x in semantic_labels], dtype=np.int)
            if self.HAS_GT_BBOX:
                bboxes[:, -1] = np.array(
                    [self.label_map[int(x)] for x in bboxes[:, -1]])

        # Normalize rotation.
        if self.augment_data and self.HAS_GT_BBOX and self.IS_ROTATION_BBOX:
            if self.config.normalize_rotation:
                rot_bin = np.floor((bboxes[:, 6] + np.pi / 4) / (np.pi / 2))
                idxs = list(range(3))
                idxs.remove(self.LOCFEAT_IDX)
                assert len(idxs) == 2
                bbox_size = (bboxes[:, 3:6] - bboxes[:, :3]) / 2
                bbox_center = (bboxes[:, 3:6] + bboxes[:, :3]) / 2
                bboxes[:, 6] = bboxes[:, 6] - rot_bin * np.pi / 2
                is_rotated = np.where(rot_bin % 2)[0]
                bbox_size[np.ix_(is_rotated, idxs)] = bbox_size[np.ix_(
                    is_rotated, list(reversed(idxs)))]
                bboxes = np.hstack((bbox_center - bbox_size,
                                    bbox_center + bbox_size, bboxes[:, 6:]))
            elif self.config.normalize_rotation2:
                bboxes[:, 6] = (bboxes[:, 6] % np.pi - np.pi / 2) * 2

        if not self.HAS_GT_BBOX:
            instance_mask = self.get_instance_mask(semantic_labels,
                                                   instance_labels)
            bboxes, instance_labels = get_bbox(coords, semantic_labels,
                                               instance_labels, instance_mask,
                                               self.ignore_mask)
        labels = np.hstack(
            (np.expand_dims(semantic_labels,
                            1), np.expand_dims(instance_labels, 1)))

        return_args = [coords, feats, labels, bboxes]
        if self.return_transformation:
            transformation = np.expand_dims(transformation, 0)
            return_args.extend([
                pointcloud.astype(np.float32),
                transformation.astype(np.float32)
            ])
        return tuple(return_args)