def testTransformBBoxes3DConsistentWithPoints(self): num_boxes, num_points = 20, 100 points = tf.random_uniform((num_points, 3)) bboxes_3d = tf.random_uniform((num_boxes, 7)) in_bboxes = geometry.IsWithinBBox3D(points, bboxes_3d) transforms = self._MakeTransformTestTranslationMatrices(1)[0] points_transformed = geometry.TransformPoints(points, transforms) bboxes_3d_transformed = geometry.TransformBBoxes3D(bboxes_3d, transforms) in_bboxes_transformed = geometry.IsWithinBBox3D(points_transformed, bboxes_3d_transformed) with self.session() as sess: actual_in_bboxes, actual_in_bboxes_transformed = sess.run( (in_bboxes, in_bboxes_transformed)) self.assertAllEqual(actual_in_bboxes, actual_in_bboxes_transformed)
def add_labels(self, feature, labels, points_xyz): """Add 3d bounding box labels into the output feature map. Args: feature: A tf.Example feature map. labels: A repeated car.open_dataset.Label proto. points_xyz: A numpy array of shape [-1, 3] with the pointcloud. This is used to calculate the number of points in each 3D bounding box. """ label_classes = [] label_ids = [] detection_difficulty_levels = [] tracking_difficulty_levels = [] bboxes = [] label_md = [] for label in labels: box = label.box bbox_3d = [ box.center_x, box.center_y, box.center_z, box.length, box.width, box.height, box.heading ] md = [ label.metadata.speed_x, label.metadata.speed_y, label.metadata.accel_x, label.metadata.accel_y ] label_md += md bboxes += bbox_3d label_classes += [label.type] label_ids += [tf.compat.as_bytes(label.id)] detection_difficulty_levels += [label.detection_difficulty_level] tracking_difficulty_levels += [label.tracking_difficulty_level] # Calculate the number of points in each ground truth box which are needed # to fill in difficulty levels for each ground truth and to filter boxes # with less points than a configurable minimum. points_xyz = tf.convert_to_tensor(points_xyz, dtype=tf.float32) bboxes_3d = tf.convert_to_tensor(np.array(bboxes).reshape(-1, 7), dtype=tf.float32) points_in_bboxes_mask = geometry.IsWithinBBox3D(points_xyz, bboxes_3d) bboxes_3d_num_points = tf.reduce_sum(tf.cast(points_in_bboxes_mask, tf.int32), axis=0, keepdims=False) bboxes_3d_num_points = bboxes_3d_num_points.numpy().reshape([-1]) bboxes = np.array(bboxes).reshape(-1) label_md = np.array(label_md).reshape(-1) feature['labels'].int64_list.value[:] = label_classes feature['label_ids'].bytes_list.value[:] = label_ids feature['detection_difficulties'].int64_list.value[:] = ( detection_difficulty_levels) feature['tracking_difficulties'].int64_list.value[:] = ( tracking_difficulty_levels) feature['bboxes_3d'].float_list.value[:] = list(bboxes) feature['label_metadata'].float_list.value[:] = list(label_md) feature['bboxes_3d_num_points'].int64_list.value[:] = list( bboxes_3d_num_points)
def _GetFilteredBoundingBoxData(kitti_data): """Given a single batch element of data, process it for writing. Args: kitti_data: A NestedMap of KITTI input generator returned data with a batch size of 1. Returns: A NestedMap of all the output data we need to write per bounding box cropped pointclouds. """ points = kitti_data.lasers.points_xyz points_feature = kitti_data.lasers.points_feature bboxes_3d = kitti_data.labels.bboxes_3d bboxes_3d_mask = kitti_data.labels.bboxes_3d_mask bboxes_3d = tf.boolean_mask(bboxes_3d, bboxes_3d_mask) if 'points_padding' in kitti_data.lasers: points_validity_mask = tf.cast(kitti_data.lasers.points_padding - 1, tf.bool) points = tf.boolean_mask(points, points_validity_mask) points_feature = tf.boolean_mask(points_feature, points_validity_mask) points_in_bboxes_mask = geometry.IsWithinBBox3D(points, bboxes_3d) output_map = py_utils.NestedMap() # Points and features contain the whole pointcloud, which we will use # per box boolean masks later in _ToTFExampleProto to subselect data per box. output_map.points = points output_map.points_feature = points_feature output_map.points_in_bboxes_mask = points_in_bboxes_mask output_map.source_id = kitti_data.labels.source_id # Add additional data output_keys = [ 'bboxes_3d', 'labels', 'texts', 'occlusion', 'difficulties', 'truncation', ] for key in output_keys: output_map[key] = tf.boolean_mask(kitti_data.labels[key], kitti_data.labels.bboxes_3d_mask) return output_map
def testIsWithinBBox3D(self): num_points, num_bboxes = 19, 4 # rotate the first box by pi / 2 so dim_x and dim_y are swapped. # The last box is a cube rotated by 45 degrees. bboxes = tf.constant([[1.0, 2.0, 3.0, 6.0, 0.4, 6.0, np.pi / 2], [4.0, 5.0, 6.0, 7.0, 0.8, 7.0, 0.0], [0.4, 0.3, 0.2, 0.1, 0.1, 0.2, 0.0], [-10., -10., -10., 3., 3., 3., np.pi / 4]], dtype=tf.float32) points = tf.constant( [ [1.0, 2.0, 3.0], # box 0 (centroid) [0.8, 2.0, 3.0], # box 0 (below x) [1.1, 2.0, 3.0], # box 0 (above x) [1.3, 2.0, 3.0], # box 0 (too far x) [0.7, 2.0, 3.0], # box 0 (too far x) [4.0, 5.0, 6.0], # box 1 (centroid) [4.0, 4.6, 6.0], # box 1 (below y) [4.0, 5.4, 6.0], # box 1 (above y) [4.0, 4.5, 6.0], # box 1 (too far y) [4.0, 5.5, 6.0], # box 1 (too far y) [0.4, 0.3, 0.2], # box 2 (centroid) [0.4, 0.3, 0.1], # box 2 (below z) [0.4, 0.3, 0.3], # box 2 (above z) [0.4, 0.3, 0.0], # box 2 (too far z) [0.4, 0.3, 0.4], # box 2 (too far z) [5.0, 7.0, 8.0], # none [1.0, 5.0, 3.6], # box0, box1 [-11.6, -10., -10.], # box3 (rotated corner point). [-11.4, -11.4, -10.], # not in box3, would be if not rotated. ], dtype=tf.float32) expected_is_inside = np.array([ [True, False, False, False], [True, False, False, False], [True, False, False, False], [False, False, False, False], [False, False, False, False], [False, True, False, False], [False, True, False, False], [False, True, False, False], [False, False, False, False], [False, False, False, False], [False, False, True, False], [False, False, True, False], [False, False, True, False], [False, False, False, False], [False, False, False, False], [False, False, False, False], [True, True, False, False], [False, False, False, True], [False, False, False, False], ]) assert points.shape[0] == num_points assert bboxes.shape[0] == num_bboxes assert expected_is_inside.shape[0] == num_points assert expected_is_inside.shape[1] == num_bboxes with self.session() as sess: is_inside = sess.run(geometry.IsWithinBBox3D(points, bboxes)) self.assertAllEqual([num_points, num_bboxes], is_inside.shape) self.assertAllEqual(expected_is_inside, is_inside)
def testIsWithinBBox3D(self): num_points, num_bboxes = 19, 4 # rotate the first box by pi / 2 so dim_x and dim_y are swapped. # The last box is a cube rotated by 45 degrees. bboxes = tf.constant([[1.0, 2.0, 3.0, 6.0, 0.4, 6.0, np.pi / 2], [4.0, 5.0, 6.0, 7.0, 0.8, 7.0, 0.0], [0.4, 0.3, 0.2, 0.1, 0.1, 0.2, 0.0], [-10., -10., -10., 3., 3., 3., np.pi / 4]], dtype=tf.float32) points = tf.constant( [ [1.0, 2.0, 3.0], # box 0 (centroid) [0.8, 2.0, 3.0], # box 0 (below x) [1.1, 2.0, 3.0], # box 0 (above x) [1.3, 2.0, 3.0], # box 0 (too far x) [0.7, 2.0, 3.0], # box 0 (too far x) [4.0, 5.0, 6.0], # box 1 (centroid) [4.0, 4.6, 6.0], # box 1 (below y) [4.0, 5.4, 6.0], # box 1 (above y) [4.0, 4.5, 6.0], # box 1 (too far y) [4.0, 5.5, 6.0], # box 1 (too far y) [0.4, 0.3, 0.2], # box 2 (centroid) [0.4, 0.3, 0.1], # box 2 (below z) [0.4, 0.3, 0.3], # box 2 (above z) [0.4, 0.3, 0.0], # box 2 (too far z) [0.4, 0.3, 0.4], # box 2 (too far z) [5.0, 7.0, 8.0], # none [1.0, 5.0, 3.6], # box0, box1 [-11.6, -10., -10.], # box3 (rotated corner point). [-11.4, -11.4, -10.], # not in box3, would be if not rotated. ], dtype=tf.float32) expected_is_inside = np.array([ [True, False, False, False], [True, False, False, False], [True, False, False, False], [False, False, False, False], [False, False, False, False], [False, True, False, False], [False, True, False, False], [False, True, False, False], [False, False, False, False], [False, False, False, False], [False, False, True, False], [False, False, True, False], [False, False, True, False], [False, False, False, False], [False, False, False, False], [False, False, False, False], [True, True, False, False], [False, False, False, True], [False, False, False, False], ]) assert points.shape[0] == num_points assert bboxes.shape[0] == num_bboxes assert expected_is_inside.shape[0] == num_points assert expected_is_inside.shape[1] == num_bboxes with self.session(): is_inside = self.evaluate(geometry.IsWithinBBox3D(points, bboxes)) self.assertAllEqual([num_points, num_bboxes], is_inside.shape) self.assertAllEqual(expected_is_inside, is_inside) # Add a batch dimension to the data and see that it still works # as expected. batch_size = 3 points = tf.tile(points[tf.newaxis, ...], [batch_size, 1, 1]) bboxes = tf.tile(bboxes[tf.newaxis, ...], [batch_size, 1, 1]) with self.session(): is_inside = self.evaluate(geometry.IsWithinBBox3D(points, bboxes)) self.assertAllEqual([batch_size, num_points, num_bboxes], is_inside.shape) for batch_idx in range(batch_size): self.assertAllEqual(expected_is_inside, is_inside[batch_idx])