Exemple #1
0
def apply_random_transform_scalar_labels(features, labels):
    """Apply a random rigid transformation to `features`.

    Features are interpolated trilinearly, and labels are unchanged because they are
    scalars.
    """
    if len(features.shape) != 3:
        raise ValueError("features must be rank 3")
    if len(labels.shape) != 1:
        raise ValueError("labels must be rank 1")
    # Rotate -180 degrees to 180 degrees in three dimensions.
    rotation = tf.random.uniform(shape=[3],
                                 minval=-np.pi,
                                 maxval=np.pi,
                                 dtype=tf.float32)

    # Translate at most 5% in any direction, so there's less chance of
    # important data going out of view.
    maxval = 0.05 * features.shape[0]
    translation = tf.random.uniform(shape=[3],
                                    minval=-maxval,
                                    maxval=maxval,
                                    dtype=tf.float32)

    volume_shape = np.asarray(features.shape)
    matrix = get_affine(volume_shape=volume_shape,
                        rotation=rotation,
                        translation=translation)
    return warp_features_labels(features=features,
                                labels=labels,
                                matrix=matrix,
                                scalar_label=True)
Exemple #2
0
def apply_random_transform(features, labels):
    """Apply a random rigid transformation to `features` and `labels`.

    The same transformation is applied to features and labels. Features are
    interpolated trilinearly, and labels are interpolated with nearest
    neighbors.
    """
    if len(features.shape) != 3 or len(labels.shape) != 3:
        raise ValueError("features and labels must be rank 3")
    if features.shape != labels.shape:
        raise ValueError("shape of features and labels must be the same.")
    # Rotate -180 degrees to 180 degrees in three dimensions.
    rotation = tf.random.uniform(shape=[3],
                                 minval=-np.pi,
                                 maxval=np.pi,
                                 dtype=tf.float32)

    # Translate at most 5% in any direction, so there's less chance of
    # important data going out of view.
    maxval = 0.05 * features.shape[0]
    translation = tf.random.uniform(shape=[3],
                                    minval=-maxval,
                                    maxval=maxval,
                                    dtype=tf.float32)

    volume_shape = np.asarray(features.shape)
    matrix = get_affine(volume_shape=volume_shape,
                        rotation=rotation,
                        translation=translation)
    return warp_features_labels(features=features,
                                labels=labels,
                                matrix=matrix)
Exemple #3
0
def _transform_and_predict(model,
                           x,
                           block_shape,
                           rotation,
                           translation=[0, 0, 0],
                           verbose=False):
    """Predict on rigidly transformed features.

    The rigid transformation is applied to the volumes prior to prediction, and
    the prediced labels are transformed with the inverse warp, so that they are
    in the same space.

    Parameters
    ----------
    model: `tf.keras.Model`, model used for prediction.
    x: 3D array, volume of features.
    block_shape: tuple of length 3, shape of non-overlapping blocks to take
        from the features. This also corresponds to the input of the model, not
        including the batch or channel dimensions.
    rotation: tuple of length 3, rotation angle in radians in each dimension.
    translation: tuple of length 3, units of translation in each dimension.
    verbose: bool, whether to print progress bar.

    Returns
    -------
    Array of predictions with the same shape and in the same space as the
    original input features.
    """

    x = np.asarray(x).astype(np.float32)
    affine = get_affine(x.shape, rotation=rotation, translation=translation)
    inverse_affine = tf.linalg.inv(affine)
    x_warped = warp(x, affine, order=1)

    x_warped_blocks = to_blocks_numpy(x_warped, block_shape)
    x_warped_blocks = x_warped_blocks[..., np.newaxis]  # add grayscale channel
    x_warped_blocks = standardize_numpy(x_warped_blocks)
    y = model.predict(x_warped_blocks, batch_size=1, verbose=verbose)

    n_classes = y.shape[-1]
    if n_classes == 1:
        y = y.squeeze(-1)
    else:
        # Usually, the argmax would be taken to get the class membership of
        # each voxel, but if we get hard values, then we cannot average
        # multiple predictions.
        raise ValueError(
            "This function is not compatible with multi-class predictions.")

    y = from_blocks_numpy(y, x.shape)
    y = warp(y, inverse_affine, order=0).numpy()

    return y