Beispiel #1
0
def test_affine_transform_type_consistency():

    image = da.ones((3, 3))
    image_t = da_ndinterp.affine_transform(image, np.eye(2), [0, 0])

    assert isinstance(image, type(image_t))
    assert isinstance(image[0, 0].compute(), type(image_t[0, 0].compute()))
Beispiel #2
0
def test_affine_transform_no_output_shape_or_chunks_specified():

    image = da.ones((3, 3))
    image_t = da_ndinterp.affine_transform(image, np.eye(2), [0, 0])

    assert image_t.shape == image.shape
    assert image_t.chunks == tuple([(s, ) for s in image.shape])
Beispiel #3
0
def test_affine_transform_numpy_input():

    image = np.ones((3, 3))
    image_t = da_ndinterp.affine_transform(image, np.eye(2), [0, 0])

    assert image_t.shape == image.shape
    assert (image == image_t).min()
Beispiel #4
0
def test_affine_transform_type_consistency_gpu():

    cupy = pytest.importorskip("cupy", minversion="6.0.0")

    image = da.ones((3, 3))
    image_t = da_ndinterp.affine_transform(image, np.eye(2), [0, 0])

    image.map_blocks(cupy.asarray)

    assert isinstance(image, type(image_t))
    assert isinstance(image[0, 0].compute(), type(image_t[0, 0].compute()))
Beispiel #5
0
def test_affine_transform_parameter_formats(n):

    # define reference parameters
    scale_factors = np.ones(n, dtype=np.float) * 2.
    matrix_n = np.diag(scale_factors)
    offset = -np.ones(n)

    # convert into different formats
    matrix_only_scaling = scale_factors
    matrix_pre_homogeneous = np.hstack((matrix_n, offset[:, None]))
    matrix_homogeneous = np.vstack((matrix_pre_homogeneous, [0] * n + [1]))

    np.random.seed(0)
    image = da.random.random([5] * n)

    # reference run
    image_t_0 = da_ndinterp.affine_transform(image, matrix_n, offset).compute()

    # assert that the different parameter formats
    # lead to the same output
    image_t_scale = da_ndinterp.affine_transform(image, matrix_only_scaling,
                                                 offset).compute()
    assert (np.allclose(image_t_0, image_t_scale))

    for matrix in [matrix_pre_homogeneous, matrix_homogeneous]:

        image_t = da_ndinterp.affine_transform(
            image,
            matrix,
            offset + 10.,  # ignored
        ).compute()

        assert (np.allclose(image_t_0, image_t))

    # catch matrices that are not homogeneous transformation matrices
    with pytest.raises(ValueError):
        matrix_not_homogeneous = np.vstack(
            (matrix_pre_homogeneous, [-1] * n + [1]))
        da_ndinterp.affine_transform(image, matrix_not_homogeneous, offset)
Beispiel #6
0
def test_affine_transform_large_input_small_output_cpu():
    """
    Make sure input array does not need to be computed entirely
    """

    # fully computed, this array would occupy 8TB
    image = da.random.random([10000] * 3, chunks=(200, 200, 200))
    image_t = da_ndinterp.affine_transform(image,
                                           np.eye(3), [0, 0, 0],
                                           output_chunks=[1, 1, 1],
                                           output_shape=[1, 1, 1])

    # if more than the needed chunks should be computed,
    # this would take long and eventually raise a MemoryError
    image_t[0, 0, 0].compute()
Beispiel #7
0
def test_affine_transform_large_input_small_output_gpu():
    """
    Make sure input array does not need to be computed entirely
    """
    cupy = pytest.importorskip("cupy", minversion="6.0.0")

    # this array would occupy more than 24GB on a GPU
    image = da.random.random([2000] * 3, chunks=(50, 50, 50))
    image.map_blocks(cupy.asarray)

    image_t = da_ndinterp.affine_transform(image,
                                           np.eye(3), [0, 0, 0],
                                           output_chunks=[1, 1, 1],
                                           output_shape=[1, 1, 1])
    # if more than the needed chunks should be computed,
    # this would take long and eventually raise a MemoryError
    image_t[0, 0, 0].compute()
Beispiel #8
0
def test_affine_transform_prefilter_warning():

    with pytest.warns(UserWarning):
        da_ndinterp.affine_transform(da.ones(3), [1], [0],
                                     order=3,
                                     prefilter=True)
Beispiel #9
0
def test_affine_transform_minimal_input():

    image = np.ones((3, 3))
    image_t = da_ndinterp.affine_transform(np.ones((3, 3)), np.eye(2))

    assert image_t.shape == image.shape
Beispiel #10
0
def validate_affine_transform(
        n=2,
        matrix=None,
        offset=None,
        input_output_shape_per_dim=(16, 16),
        interp_order=1,
        interp_mode='constant',
        input_output_chunksize_per_dim=(6, 6),
        random_seed=0,
        use_cupy=False,
):
    """
    Compare the outputs of `ndimage.affine_transformation`
    and `dask_image.ndinterp.affine_transformation`.

    Notes
    -----
        Currently, prefilter is disabled and therefore the output
        of `dask_image.ndinterp.affine_transformation` is compared
        to `prefilter=False`.
    """

    # define test image
    a = input_output_shape_per_dim[0]
    np.random.seed(random_seed)
    image = np.random.random([a] * n)

    # transform into dask array
    chunksize = [input_output_chunksize_per_dim[0]] * n
    image_da = da.from_array(image, chunks=chunksize)
    if use_cupy:
        import cupy as cp
        image_da = image_da.map_blocks(cp.asarray)

    # define (random) transformation
    if matrix is None:
        # make sure to substantially deviate from unity matrix
        matrix = np.eye(n) + (np.random.random((n, n)) - 0.5) * 5.
    if offset is None:
        offset = (np.random.random(n) - 0.5) / 5. * np.array(image.shape)

    # define resampling options
    output_shape = [input_output_shape_per_dim[1]] * n
    output_chunks = [input_output_chunksize_per_dim[1]] * n

    # transform with scipy
    image_t_scipy = ndimage.affine_transform(image,
                                             matrix,
                                             offset,
                                             output_shape=output_shape,
                                             order=interp_order,
                                             mode=interp_mode,
                                             prefilter=False)

    # transform with dask-image
    image_t_dask = da_ndinterp.affine_transform(image_da,
                                                matrix,
                                                offset,
                                                output_shape=output_shape,
                                                output_chunks=output_chunks,
                                                order=interp_order,
                                                mode=interp_mode)
    image_t_dask_computed = image_t_dask.compute()

    assert np.allclose(image_t_scipy, image_t_dask_computed)
Beispiel #11
0
def _transform_array(image: da.Array,
                     scale: Tuple[float, ...],
                     offset: Tuple[float, ...],
                     shape: Tuple[int, ...],
                     chunks: Optional[Tuple[int, ...]],
                     spline_order: int,
                     recover_nan: bool) -> da.Array:
    """
    Apply affine transformation to ND-image.

    :param image: ND-image with shape (..., size_y, size_x)
    :param scale: Scaling factors (1, ..., 1, sy, sx)
    :param offset: Offset values (0, ..., 0, oy, ox)
    :param shape: (..., size_y, size_x)
    :param chunks: (..., chunk_size_y, chunk_size_x)
    :param spline_order: 0 ... 5
    :param recover_nan: True/False
    :return: Transformed ND-image.
    """
    assert_true(len(scale) == image.ndim, 'invalid scale')
    assert_true(len(offset) == image.ndim, 'invalid offset')
    assert_true(len(shape) == image.ndim, 'invalid shape')
    assert_true(chunks is None or len(chunks) == image.ndim,
                'invalid chunks')
    if _is_no_op(image, scale, offset, shape):
        return image
    # As of scipy 0.18, matrix = scale is no longer supported.
    # Therefore we use the diagonal matrix form here,
    # where scale is the diagonal.
    matrix = np.diag(scale)
    at_kwargs = dict(
        offset=offset,
        order=spline_order,
        output_shape=shape,
        output_chunks=chunks,
        mode='constant',
    )
    if recover_nan and spline_order > 0:
        # We can "recover" values that are neighbours to NaN values
        # that would otherwise become NaN too.
        mask = da.isnan(image)
        # First check if there are NaN values ar all
        if da.any(mask):
            # Yes, then
            # 1. replace NaN by zero
            filled_im = da.where(mask, 0.0, image)
            # 2. transform the zeo-filled image
            scaled_im = ndinterp.affine_transform(filled_im,
                                                  matrix,
                                                  **at_kwargs,
                                                  cval=0.0)
            # 3. transform the inverted mask
            scaled_norm = ndinterp.affine_transform(1.0 - mask,
                                                    matrix,
                                                    **at_kwargs,
                                                    cval=0.0)
            # 4. put back NaN where there was zero,
            #    otherwise decode using scaled mask
            return da.where(da.isclose(scaled_norm, 0.0),
                            np.nan, scaled_im / scaled_norm)

    # No dealing with NaN required
    return ndinterp.affine_transform(image, matrix, **at_kwargs, cval=np.nan)