def TransformFeatures()

in lingvo/tasks/car/input_preprocessors.py [0:0]


  def TransformFeatures(self, features):
    p = self.params

    num_features = features.lasers.points_feature.shape[-1]

    def Transform(i, state):
      """Transform the points in bounding box `i`."""
      state.points_xyz = tf.reshape(state.points_xyz, [-1, 3])
      bbox_mask = tf.reshape(state.points_in_bbox_mask[:, i], [-1])

      # Fetch only the points in the bounding box.
      points_xyz_masked = tf.boolean_mask(state.points_xyz, bbox_mask)
      points_feature_masked = tf.boolean_mask(state.points_feature, bbox_mask)

      num_points = tf.shape(points_xyz_masked)[0]

      # TODO(vrv): Fold the following into a single transformation
      # matrix.
      #
      # Translate the box to the origin, then rotate the desired
      # rotation angle.
      translation_vec = state.bboxes_3d[i, 0:3]
      rotation_vec = [state.rotation[i], 0., 0.]
      pose = tf.concat([-translation_vec, rotation_vec], axis=0)
      points_xyz_adj = geometry.CoordinateTransform(points_xyz_masked, pose)
      if p.max_scaling is not None or p.max_shearing is not None:
        # Translate the points in the bounding box by moving dz/2 so that the
        # bottom of the bounding box is at Z = 0 when any of the two
        # (max_scaling or max_shearing) is not None
        translation_scale_or_shear = tf.stack(
            [0., 0., state.bboxes_3d[i, 5] / 2], axis=0)
        pose1 = tf.concat([translation_scale_or_shear, [0., 0., 0.]], axis=0)
        points_xyz_adj = geometry.CoordinateTransform(points_xyz_adj, pose1)
      else:
        translation_scale_or_shear = tf.stack([0., 0., 0.], axis=0)

      if p.max_scaling is not None:
        # Perform scaling to the point cloud
        # Scaling matrix
        # [[s_x+1    0      0]
        #  [ 0      s_y+1   0]
        #  [ 0       0     s_z+1]]
        sx = tf.random.uniform([],
                               minval=-p.max_scaling[0],
                               maxval=p.max_scaling[0],
                               seed=p.random_seed)
        sy = tf.random.uniform([],
                               minval=-p.max_scaling[1],
                               maxval=p.max_scaling[1],
                               seed=p.random_seed)
        sz = tf.random.uniform([],
                               minval=-p.max_scaling[2],
                               maxval=p.max_scaling[2],
                               seed=p.random_seed)
        scaling_matrix = tf.stack(
            [[sx + 1., 0., 0.], [0., sy + 1., 0.], [0., 0., sz + 1.]], axis=0)

        points_xyz_adj = tf.einsum('ij,kj->ki', scaling_matrix, points_xyz_adj)

      if p.max_shearing is not None:
        # Perform shearing to the point cloud
        # Shearing matrix
        # [[1       sh_x^y  sh_x^z]
        #  [sh_y^x     1    sh_y^z]
        #  [sh_z^x  sh_z^y     1  ]]
        sxy = tf.random.uniform([],
                                minval=-p.max_shearing[0],
                                maxval=p.max_shearing[0],
                                seed=p.random_seed)
        sxz = tf.random.uniform([],
                                minval=-p.max_shearing[1],
                                maxval=p.max_shearing[1],
                                seed=p.random_seed)
        syx = tf.random.uniform([],
                                minval=-p.max_shearing[2],
                                maxval=p.max_shearing[2],
                                seed=p.random_seed)
        syz = tf.random.uniform([],
                                minval=-p.max_shearing[3],
                                maxval=p.max_shearing[3],
                                seed=p.random_seed)
        szx = tf.random.uniform([],
                                minval=-p.max_shearing[4],
                                maxval=p.max_shearing[4],
                                seed=p.random_seed)
        szy = tf.random.uniform([],
                                minval=-p.max_shearing[5],
                                maxval=p.max_shearing[5],
                                seed=p.random_seed)
        shearing_matrix = tf.stack(
            [[1., sxy, sxz], [syx, 1., syz], [szx, szy, 1.]], axis=0)
        points_xyz_adj = tf.einsum('ij,kj->ki', shearing_matrix, points_xyz_adj)

      # Translate the points back, adding noise if needed.
      translation_with_noise = (
          translation_vec - translation_scale_or_shear +
          state.translate_pose[i])
      pose2 = tf.concat([translation_with_noise, [0., 0., 0.]], axis=0)
      final_points_xyz = geometry.CoordinateTransform(points_xyz_adj, pose2)

      # final_points_xyz is an [M, 3] Tensor where M is the number of points in
      # the box.
      points_mask = tf.ones([num_points], dtype=tf.float32)

      final_points_xyz = py_utils.PadOrTrimTo(final_points_xyz,
                                              [p.max_num_points_per_bbox, 3])
      final_points_feature = py_utils.PadOrTrimTo(
          points_feature_masked, [p.max_num_points_per_bbox, num_features])
      points_mask = py_utils.PadOrTrimTo(points_mask,
                                         [p.max_num_points_per_bbox])
      state.out_bbox_points = inplace_ops.alias_inplace_update(
          state.out_bbox_points, [i], tf.expand_dims(final_points_xyz, 0))
      state.out_bbox_feature = inplace_ops.alias_inplace_update(
          state.out_bbox_feature, [i], tf.expand_dims(final_points_feature, 0))
      state.out_bbox_mask = inplace_ops.alias_inplace_update(
          state.out_bbox_mask, [i], tf.expand_dims(points_mask, 0))

      return state

    # Get the points and features that reside in boxes.
    if 'points_padding' in features.lasers:
      points_mask = 1 - features.lasers.points_padding
      points_xyz = tf.boolean_mask(features.lasers.points_xyz, points_mask)
      points_feature = tf.boolean_mask(features.lasers.points_feature,
                                       points_mask)
    else:
      points_xyz = features.lasers.points_xyz
      points_feature = features.lasers.points_feature

    # Fetch real bounding boxes and compute point mask.
    real_bboxes_3d = tf.boolean_mask(features.labels.bboxes_3d,
                                     features.labels.bboxes_3d_mask)
    points_in_bbox_mask = geometry.IsWithinBBox3D(points_xyz, real_bboxes_3d)

    # Choose a random rotation for every real box.
    num_boxes = tf.shape(real_bboxes_3d)[0]
    rotation = tf.random.uniform([num_boxes],
                                 minval=-p.max_rotation,
                                 maxval=p.max_rotation,
                                 seed=p.random_seed)

    base_seed = p.random_seed
    x_seed = base_seed
    y_seed = None if base_seed is None else base_seed + 1
    z_seed = None if base_seed is None else base_seed + 2
    random_translate_x = tf.random.normal([num_boxes],
                                          mean=0.0,
                                          stddev=p.noise_std[0],
                                          seed=x_seed)
    random_translate_y = tf.random.normal([num_boxes],
                                          mean=0.0,
                                          stddev=p.noise_std[1],
                                          seed=y_seed)
    random_translate_z = tf.random.normal([num_boxes],
                                          mean=0.0,
                                          stddev=p.noise_std[2],
                                          seed=z_seed)

    translate_pose = tf.stack(
        [random_translate_x, random_translate_y, random_translate_z], axis=1)

    fg_xyz, fg_feature = self._Foreground(features, points_xyz, points_feature,
                                          real_bboxes_3d, points_in_bbox_mask,
                                          rotation, translate_pose, Transform)

    # Concatenate them with the background points and features.
    bg_xyz, bg_feature = self._Background(points_xyz, points_feature,
                                          points_in_bbox_mask)
    all_points = tf.concat([bg_xyz, fg_xyz], axis=0)
    all_features = tf.concat([bg_feature, fg_feature], axis=0)

    # Shuffle the points/features randomly.
    all_points, all_features = _ConsistentShuffle((all_points, all_features),
                                                  p.random_seed)

    # Padding should technically be unnecessary: the number of points before and
    # after should be the same, but in practice we sometimes seem to drop a few
    # points, and so we pad to make the shape fixed.
    #
    # TODO(vrv): Identify the source of this problem and then assert a shape
    # matching check.
    if 'points_padding' in features.lasers:
      features.lasers.points_xyz = py_utils.PadOrTrimTo(
          all_points, tf.shape(features.lasers.points_xyz))
      features.lasers.points_feature = py_utils.PadOrTrimTo(
          all_features, tf.shape(features.lasers.points_feature))
      total_points = tf.shape(all_points)[0]
      features.lasers.points_padding = 1.0 - py_utils.PadOrTrimTo(
          tf.ones([total_points]), tf.shape(features.lasers.points_padding))
    else:
      features.lasers.points_xyz = all_points
      features.lasers.points_feature = all_features

    # Translate noise.
    bboxes_xyz = real_bboxes_3d[..., :3]
    bboxes_xyz += translate_pose[..., :3]

    bboxes_dim = real_bboxes_3d[..., 3:6]
    # Rotate bboxes by their corresponding rotation.
    bboxes_rot = real_bboxes_3d[..., 6:]
    bboxes_rot -= rotation[:, tf.newaxis]
    features.labels.bboxes_3d = py_utils.PadOrTrimTo(
        tf.concat([bboxes_xyz, bboxes_dim, bboxes_rot], axis=-1),
        tf.shape(features.labels.bboxes_3d))
    features.labels.bboxes_3d_mask = py_utils.PadOrTrimTo(
        tf.ones(tf.shape(real_bboxes_3d)[0]),
        tf.shape(features.labels.bboxes_3d_mask))
    return features