def compute_xyz(depth_img, fx, fy, px, py, height, width):
    indices = util_.build_matrix_of_indices(height, width)
    z_e = depth_img
    x_e = (indices[..., 1] - px) * z_e / fx
    y_e = (indices[..., 0] - py) * z_e / fy
    xyz_img = np.stack([x_e, y_e, z_e], axis=-1)  # Shape: [H x W x 3]
    return xyz_img
def compute_xyz(depth_img, camera_params):
    """ Compute ordered point cloud from depth image and camera parameters.

        If focal lengths fx,fy are stored in the camera_params dictionary, use that.
        Else, assume camera_params contains parameters used to generate synthetic data (e.g. fov, near, far, etc)

        @param depth_img: a [H x W] numpy array of depth values in meters
        @param camera_params: a dictionary with parameters of the camera used 
    """

    # Compute focal length from camera parameters
    if 'fx' in camera_params and 'fy' in camera_params:
        fx = camera_params['fx']
        fy = camera_params['fy']
    else:  # simulated data
        aspect_ratio = camera_params['img_width'] / camera_params['img_height']
        e = 1 / (np.tan(np.radians(camera_params['fov'] / 2.)))
        t = camera_params['near'] / e
        b = -t
        r = t * aspect_ratio
        l = -r
        alpha = camera_params['img_width'] / (r - l)  # pixels per meter
        focal_length = camera_params[
            'near'] * alpha  # focal length of virtual camera (frustum camera)
        fx = focal_length
        fy = focal_length

    if 'x_offset' in camera_params and 'y_offset' in camera_params:
        x_offset = camera_params['x_offset']
        y_offset = camera_params['y_offset']
    else:  # simulated data
        x_offset = camera_params['img_width'] / 2
        y_offset = camera_params['img_height'] / 2

    indices = util_.build_matrix_of_indices(camera_params['img_height'],
                                            camera_params['img_width'])
    z_e = depth_img
    x_e = (indices[..., 1] - x_offset) * z_e / fx
    y_e = (indices[..., 0] - y_offset) * z_e / fy
    xyz_img = np.stack([x_e, y_e, z_e], axis=-1)  # Shape: [H x W x 3]

    return xyz_img
def random_rotation(label):
    """ Randomly rotate mask

        @param label: a [H x W] numpy array of {0, 1}
    """
    H, W = label.shape

    num_tries = 0
    valid_transform = False
    while not valid_transform:

        if num_tries >= cfg.TRAIN.max_augmentation_tries:
            print('Rotate: Exhausted number of augmentation tries...')
            return label

        # Rotate about center of box
        pixel_indices = util_.build_matrix_of_indices(H, W)
        h_idx, w_idx = np.where(label)
        mean = np.mean(pixel_indices[h_idx, w_idx, :],
                       axis=0)  # Shape: [2]. y_center, x_center

        # Sample an angle
        applied_angle = np.random.uniform(-cfg.TRAIN.rotation_angle_max,
                                          cfg.TRAIN.rotation_angle_max)

        rotated_label = rotate(label,
                               applied_angle,
                               center=tuple(mean[::-1]),
                               interpolation=cv2.INTER_NEAREST)
        # Make sure the mass is reasonable
        if (np.count_nonzero(rotated_label) / rotated_label.size > 0.001) and \
           (np.count_nonzero(rotated_label) / rotated_label.size < 0.98):
            valid_transform = True
        num_tries += 1

    return rotated_label
def random_ellipses(label):
    """ Randomly add/drop a few ellipses in the mask
        This is adapted from the DexNet 2.0 code.
        Their code: https://github.com/BerkeleyAutomation/gqcnn/blob/75040b552f6f7fb264c27d427b404756729b5e88/gqcnn/sgd_optimizer.py

        @param label: a [H x W] numpy array of {0, 1}
    """
    H, W = label.shape

    num_tries = 0
    valid_transform = False
    while not valid_transform:

        if num_tries >= cfg.TRAIN.max_augmentation_tries:
            print('Ellipse: Exhausted number of augmentation tries...')
            return label

        new_label = label.copy()

        # Sample number of ellipses to include/dropout
        num_ellipses = np.random.poisson(cfg.TRAIN.num_ellipses_mean)

        # Sample ellipse centers by sampling from Gaussian at object center
        pixel_indices = util_.build_matrix_of_indices(H, W)
        h_idx, w_idx = np.where(new_label)
        mu = np.mean(pixel_indices[h_idx, w_idx, :],
                     axis=0)  # Shape: [2]. y_center, x_center
        sigma = 2 * np.cov(pixel_indices[h_idx, w_idx, :].T)  # Shape: [2 x 2]
        if np.any(np.isnan(mu)) or np.any(np.isnan(sigma)):
            print(mu, sigma, h_idx, w_idx)
        ellipse_centers = np.random.multivariate_normal(
            mu, sigma, size=num_ellipses)  # Shape: [num_ellipses x 2]
        ellipse_centers = np.round(ellipse_centers).astype(int)

        # Sample ellipse radii and angles
        x_min, y_min, x_max, y_max = util_.mask_to_tight_box(new_label)
        scale_factor = max(
            x_max - x_min, y_max -
            y_min) * cfg.TRAIN.ellipse_size_percentage  # Mean of gamma r.v.
        x_radii = np.random.gamma(cfg.TRAIN.ellipse_gamma_base_shape *
                                  scale_factor,
                                  cfg.TRAIN.ellipse_gamma_base_scale,
                                  size=num_ellipses)
        y_radii = np.random.gamma(cfg.TRAIN.ellipse_gamma_base_shape *
                                  scale_factor,
                                  cfg.TRAIN.ellipse_gamma_base_scale,
                                  size=num_ellipses)
        angles = np.random.randint(0, 360, size=num_ellipses)

        # Dropout ellipses
        for i in range(num_ellipses):
            center = ellipse_centers[i, :]
            x_radius = np.round(x_radii[i]).astype(int)
            y_radius = np.round(y_radii[i]).astype(int)
            angle = angles[i]

            # include or dropout the ellipse
            mask = np.zeros_like(new_label)
            mask = cv2.ellipse(mask,
                               tuple(center[::-1]), (x_radius, y_radius),
                               angle=angle,
                               startAngle=0,
                               endAngle=360,
                               color=1,
                               thickness=-1)
            if np.random.rand() < 0.5:
                new_label[mask == 1] = 0  # Drop out ellipse
            else:
                new_label[mask == 1] = 1  # Add ellipse

        # Make sure the mass is reasonable
        if (np.count_nonzero(new_label) / new_label.size > 0.001) and \
           (np.count_nonzero(new_label) / new_label.size < 0.98):
            valid_transform = True

        num_tries += 1

    return new_label