예제 #1
0
    def test_composition_intermediate(self, interpolation, border_mode):
        """Test that composing two opposite translations results in an identity (almost)"""

        shape = (400, 200)

        matrix_1 = np.array([[1, 0, 1], [0, 1, 1], [0, 0, 1]])
        matrix_2 = np.array([[1, 0, -1], [0, 1, -1], [0, 0, 1]])
        matrix_id = np.eye(3)

        df_1 = DisplacementField.generate(shape,
                                          approach="affine",
                                          matrix=matrix_1)
        df_2 = DisplacementField.generate(shape,
                                          approach="affine",
                                          matrix=matrix_2)

        df_id = DisplacementField.generate(shape,
                                           approach="affine",
                                           matrix=matrix_id)

        res = df_2(df_1, interpolation=interpolation, border_mode=border_mode)

        # Works only inside:D
        assert np.allclose(res.delta_x[2:-2, 2:-2], df_id.delta_x[2:-2, 2:-2])
        assert np.allclose(res.delta_y[2:-2, 2:-2], df_id.delta_y[2:-2, 2:-2])
예제 #2
0
    def test_no_inputs_anchor_corners(self):
        """Test that can/cannot instantiate with no inputs and with/without anchoring corners."""

        shape = (40, 50)
        with pytest.raises(ValueError):
            DisplacementField.generate(shape,
                                       approach="control_points",
                                       anchor_corners=False)

        DisplacementField.generate(shape,
                                   approach="control_points",
                                   anchor_corners=True)
예제 #3
0
    def test_illegal_kwarg(self):
        """Test that illegal kwarg not accepted"""

        with pytest.raises(ValueError):
            shape = (20, 13)
            DisplacementField.generate(
                shape,
                approach="edge_stretching",
                edge_mask=np.zeros(shape, dtype=bool),
                n_perturbation_points=10,
                i_am_illegal=1,
            )
예제 #4
0
    def test_displacement_field(self, tmp_path, img_grayscale):
        """Make sure that the displacement extracted can reproduce the registered moving image.

        Done by comparing with the image contained in the registration output.
        """

        fixed_img = img_grayscale
        size = fixed_img.shape
        df = DisplacementField.generate(
            size, approach="affine_simple", translation_x=20, translation_y=20
        )
        moving_img = df.warp(img_grayscale)

        df_final, meta = antspy_registration(fixed_img, moving_img, path=tmp_path)
        img1 = meta["warpedmovout"].numpy()
        img2 = df_final.warp(
            moving_img, interpolation="linear", border_mode="constant", c=0
        )

        if img_grayscale.dtype == "uint8":
            epsilon = 1
        else:
            epsilon = 0.005

        assert abs(img1 - img2).mean() < epsilon
예제 #5
0
    def test_different_types(
        self, tmp_path, monkeypatch, img_grayscale_uint, img_grayscale_float
    ):
        """Make sure that the registration does not depend on the type of input images.

        Notes
        -----
        Marked as `todo` because we did not find a way how to force ANTsPY to be always reproducible.
        """

        monkeypatch.setenv("ANTS_RANDOM_SEED", "4")
        monkeypatch.setenv("ITK_GLOBAL_DEFAULT_NUMBER_OF_THREADS", "1")

        size = img_grayscale_uint.shape
        p = img_grayscale_uint / np.sum(img_grayscale_uint)
        df = DisplacementField.generate(size, approach="paper", p=p)
        moving_img_uint = df.warp(img_grayscale_uint)
        moving_img_float = df.warp(img_grayscale_float)

        df_final1, meta1 = antspy_registration(
            img_grayscale_uint, moving_img_uint, path=tmp_path, verbose=False
        )
        df_final2, meta2 = antspy_registration(
            img_grayscale_float, moving_img_float, path=tmp_path, verbose=False
        )

        assert np.allclose(df_final1.delta_x, df_final2.delta_x, atol=0.1)
        assert np.allclose(df_final1.delta_y, df_final2.delta_y, atol=0.1)
예제 #6
0
    def generate_mov2art(img_mov, verbose=True, radius_max=60, use_normal=True):
        """Generate geometric augmentation and its inverse."""
        shape = img_mov.shape
        img_mov_float = img_as_float32(img_mov)
        edge_mask = canny(img_mov_float)

        if use_normal:
            c = np.random.normal(0.7, 0.3)
        else:
            c = np.random.random()

        if verbose:
            print("Scalar: {}".format(c))

        mov2art = c * DisplacementField.generate(
            shape,
            approach="edge_stretching",
            edge_mask=edge_mask,
            interpolation_method="rbf",
            interpolator_kwargs={"function": "linear"},
            n_perturbation_points=6,
            radius_max=radius_max,
        )

        return mov2art
예제 #7
0
    def test_warp_invariance(self, img, h_delta, w_delta):
        """Test that df_resized.warp(img) ~ resized(df.warp(img))."""
        shape = img.shape
        new_shape = (shape[0] + h_delta, shape[1] + w_delta)

        assert (new_shape[0] > 0 and new_shape[1] > 0
                )  # if not satisfied fixture image too small

        # Zoom in
        df = DisplacementField.generate(shape,
                                        approach="affine_simple",
                                        scale_x=0.8)

        df_resized = df.resize(new_shape)
        img_1 = df_resized.warp(img)
        img_2 = resize(df.warp(img), new_shape,
                       preserve_range=True)  # preserving dtype

        # WARNING MAKE SURE THAT DOES NOT RUN INTO OVERFLOW FOR UINT8
        adiff = abs(np.subtract(img_1, img_2, dtype="float"))

        if img.dtype == np.uint8:
            eps = 25
        elif img.dtype == np.float32:
            eps = 1e-1
        else:
            raise ValueError(
                "This test is only made for uint8 and float32 images.")

        assert np.median(adiff) < eps
예제 #8
0
    def test_small_shift(self, translation_xy, approach, dtype):
        """Test that small shifts do not affect the warp.

        Notes
        -----
        Anything that is withing a diameter of 1 (=radius of 0.5) should be assigned to the same point.

        """
        translation_x, translation_y = translation_xy
        shape = (9, 10)

        random_state = 1
        df = DisplacementField.generate(
            shape,
            approach="affine_simple",
            translation_x=translation_x,
            translation_y=translation_y,
        )

        np.random.seed(random_state)
        img = np.random.randint(256, size=shape).astype(dtype)

        img_warped = df.warp_annotation(img, approach=approach)

        assert np.all(img_warped == img)
예제 #9
0
    def test_wrong_inputs_1(self):
        """Test that inconsistent input lengths lead to an error."""

        shape = (40, 50)
        points = np.array([[0, 1], [10, 10]])  # len(points) = 2
        values_delta_x = np.array([0, 10, 0])  # len(values_delta_x) = 3
        values_delta_y = np.array([0, 10])  # len(values_delta_y) = 2

        with pytest.raises(ValueError):
            DisplacementField.generate(
                shape,
                approach="control_points",
                points=points,
                values_delta_x=values_delta_x,
                values_delta_y=values_delta_y,
            )
예제 #10
0
def test_construction(approach):
    """Just check default factory methods are able to construct the class with no additional parameters."""

    shape = (500, 500)
    inst = DisplacementField.generate(shape, approach=approach)

    assert isinstance(inst, DisplacementField)
예제 #11
0
    def test_basic(self, batch_size, a):
        """Basic functionality"""

        (h, w) = 356 // 2, 420 // 2

        a_tensor = Input((2, 3))
        layer = Affine2DVF((h, w))
        x = layer(a_tensor)

        assert isinstance(x, tf.Tensor)
        assert x.shape.ndims == 4
        assert K.int_shape(x) == (None, h, w, 2)

        model = Model(inputs=a_tensor, outputs=x)

        # Initialize
        a_input = np.zeros((batch_size, 2, 3))
        dvfs_true = np.zeros((batch_size, h, w, 2))

        for i in range(batch_size):
            # add random translation for each sample
            a_input[i] = a + np.hstack((np.zeros(
                (2, 2)), np.random.uniform(-10, 10, size=(2, 1))))
            df = DisplacementField.generate((h, w),
                                            approach="affine",
                                            matrix=a_input[i])

            dvfs_true[i, :, :, 0] = df.delta_x
            dvfs_true[i, :, :, 1] = df.delta_y

        # run
        dvfs_pred = model.predict(a_input)

        assert dvfs_pred.shape == (batch_size, h, w, 2)
        assert np.allclose(dvfs_true, dvfs_pred, atol=0.01)
예제 #12
0
    def test_float_values(self, img_grayscale_float, metric):
        """Test that every image similarity metrics output a float."""

        size = img_grayscale_float.shape
        img_true = img_grayscale_float
        df = DisplacementField.generate(size,
                                        approach="affine_simple",
                                        rotation=1)
        img_pred = df.warp(img_grayscale_float)

        metric_callable = ALL_IMG_METRICS[metric]

        # UNMASKED
        assert isinstance(metric_callable(img_true, img_pred), float)

        # MASKED
        mask = np.zeros(size, dtype=bool)
        mask[size[0] // 3:2 * (size[1] // 3),
             size[0] // 3:2 * (size[1] // 3)] = True

        try:
            assert isinstance(metric_callable(img_true, img_pred, mask=mask),
                              float)

        except TypeError:
            # mask keyword argument not present
            pass
예제 #13
0
def test_reproducible(random_state, approach):
    """Test that the same random seeds lead to identical result whereas different ones do not."""
    shape = (100, 120)

    df_1 = DisplacementField.generate(shape,
                                      approach=approach,
                                      random_state=random_state)
    df_2 = DisplacementField.generate(shape,
                                      approach=approach,
                                      random_state=random_state)
    df_3 = DisplacementField.generate(shape,
                                      approach=approach,
                                      random_state=random_state + 1)

    assert df_1 == df_2
    assert df_1 != df_3
예제 #14
0
    def test_wrong_inputs_0(self):
        """ Test that other types then np.ndarray lead to an error"""

        shape = (40, 50)
        points = "fake"
        values_delta_x = (1, 2, 3)
        values_delta_y = [1, 1312, "aaa"]

        with pytest.raises(TypeError):
            DisplacementField.generate(
                shape,
                approach="control_points",
                points=points,
                values_delta_x=values_delta_x,
                values_delta_y=values_delta_y,
            )
예제 #15
0
    def test_wrong_inputs_3(self):
        """Test that other dimensions are also correct."""

        shape = (40, 50)
        points = np.zeros([1, 2, 3, 4, 5])  # Wrong - needs to be a 2d array
        values_delta_x = np.array([1, 2, 3, 4, 5])
        values_delta_y = np.array([1, 2, 3, 4, 5])

        with pytest.raises(ValueError):
            DisplacementField.generate(
                shape,
                approach="control_points",
                points=points,
                values_delta_x=values_delta_x,
                values_delta_y=values_delta_y,
            )
예제 #16
0
    def test_identity(self):
        shape = (10, 11)

        df = DisplacementField.generate(shape, approach="identity")

        df_anchored = df.anchor(ds_f=1)

        assert df == df_anchored
예제 #17
0
    def test_wrong_inputs_4(self):
        """Test that out of range control points lead to an error."""

        shape = (40, 50)
        points = np.array([[100, 10], [12,
                                       12]])  # Wrong - needs to be a 2d array
        values_delta_x = np.array([1, 2])
        values_delta_y = np.array([0, 13])

        with pytest.raises(IndexError):
            DisplacementField.generate(
                shape,
                approach="control_points",
                points=points,
                values_delta_x=values_delta_x,
                values_delta_y=values_delta_y,
            )
예제 #18
0
def minimal_vol(monkeypatch):
    sn = [1, 13]
    mov_imgs = 2 * [np.zeros((12, 13))]
    dvfs = 2 * [DisplacementField.generate((12, 13), approach="identity")]

    nvol_mock = MagicMock()
    nvol_mock.__getitem__.return_value = np.zeros((len(mov_imgs), 12, 13, 1))
    monkeypatch.setattr("atlalign.volume.nissl_volume", lambda: nvol_mock)

    return Volume(sn, mov_imgs, dvfs)
예제 #19
0
    def test_wrong_inputs_5(self, metric_name):
        """Wrong input type"""

        y_true = np.zeros((2, 20, 12, 2))
        y_pred = [
            DisplacementField.generate((20, 12), approach="identity"), "faaake"
        ]

        with pytest.raises(TypeError):
            ALL_DVF_METRICS[metric_name](y_true, y_pred)
예제 #20
0
    def test_dtype_conversions(self, img, interpolation, border_mode):
        """Test that dtype is conserved (at least for uint8 and float32)"""

        df = DisplacementField.generate(img.shape, approach="identity")

        warped_img = df.warp(img,
                             interpolation=interpolation,
                             border_mode=border_mode)

        assert warped_img.dtype == img.dtype
예제 #21
0
    def test_animation(self, img):
        """Possible to generate animations."""

        df = DisplacementField.generate(img.shape, approach="identity")

        ani = create_animation(df, img)
        ani_many = create_animation([df, df], img)

        assert isinstance(ani, animation.Animation)
        assert isinstance(ani_many, animation.Animation)
예제 #22
0
    def test_invalid_names(self):
        shape = (10, 11)
        img = np.zeros(shape)

        df = DisplacementField.generate(shape, approach="identity")

        with pytest.raises(KeyError):
            df.warp(img, interpolation="fake_interpolation")

        with pytest.raises(KeyError):
            df.warp(img, border_mode="fake_border_mode")
예제 #23
0
    def test_conversion_possible(self, df_is, metric_name):
        """List of DisplacementField instances to ndarray."""

        custom_list = [
            DisplacementField.generate((20, 12), approach="identity")
            for _ in range(2)
        ]

        y_true = np.zeros((2, 20, 12, 2)) if df_is == "pred" else custom_list
        y_pred = np.zeros((2, 20, 12, 2)) if df_is == "true" else custom_list

        _, _ = ALL_DVF_METRICS[metric_name](y_true, y_pred)
예제 #24
0
def df_id(request):
    """Generate an identity transformation.

    In order to specify a shape one decorates the test function in the following way:
     `@pytest.mark.parametrize('df_id', [(320, 456)], indirect=True)`

    """
    if hasattr(request, "param"):
        shape = request.param
    else:
        shape = (10, 11)
    return DisplacementField.generate(shape, approach="identity")
예제 #25
0
    def test_returns_new_array(self, img, interpolation, border_mode):
        """Test that new image is saved in a new array."""

        shape = img.shape[:2]

        df = DisplacementField.generate(shape, approach="identity")

        img_warped = df.warp(img,
                             interpolation=interpolation,
                             border_mode=border_mode)

        assert not np.may_share_memory(img, img_warped)
        assert not np.shares_memory(img, img_warped)
예제 #26
0
    def test_wrong_inputs_2(self):
        """Test that no control points are not allowed.

        Notes
        -----
        Note that if all 3 inputs are None and anchor_corners is True,
        then automatically generates 4 control points in the background.
        """

        shape = (40, 50)
        points = np.zeros((0, 2))
        values_delta_x = np.array([])
        values_delta_y = np.array([])

        with pytest.raises(ValueError):
            DisplacementField.generate(
                shape,
                approach="control_points",
                points=points,
                values_delta_x=values_delta_x,
                values_delta_y=values_delta_y,
            )
예제 #27
0
    def test_basic(self, monkeypatch):
        shape = (10, 11)
        df = DisplacementField.generate(shape, approach="identity")

        fake_ax = Mock()
        fake_plt = Mock()
        fake_plt.subplots = lambda *args, **kwargs: (None, fake_ax)

        monkeypatch.setattr("atlalign.base.plt", fake_plt)

        df.plot_ranges()

        assert fake_ax.scatter.call_count > 0
        assert fake_ax.legend.call_count > 0
예제 #28
0
    def test_no_edges(self):
        """Test that no edges lead to identity mapping."""

        shape = (20, 13)
        # No edges
        df_1 = DisplacementField.generate(
            shape,
            approach="edge_stretching",
            edge_mask=np.zeros(shape, dtype=bool),
            n_perturbation_points=10,
        )

        # No perturbation points
        df_2 = DisplacementField.generate(
            shape,
            approach="edge_stretching",
            edge_mask=np.ones(shape, dtype=bool),
            n_perturbation_points=0,
        )

        df_id = DisplacementField(np.zeros(shape), np.zeros(shape))

        assert df_id == df_1
        assert df_id == df_2
예제 #29
0
    def test_scale(self, scale):
        """Make sure that one can scale."""

        shape = (40, 50)
        matrix = scale * np.array([[1, 0, 0], [0, 1, 0]])

        x, y = np.meshgrid(list(range(shape[1])), list(range(shape[0])))
        delta_x = scale * x - x
        delta_y = scale * y - y

        df = DisplacementField.generate(shape=shape,
                                        approach="affine",
                                        matrix=matrix)
        df_true = DisplacementField(delta_x, delta_y)

        assert df == df_true
예제 #30
0
    def test_approaches_equivalent(self, dtype):
        """Make sure approaches equivalent"""
        shape = (10, 11)

        img = np.random.randint(1, 256, size=shape).astype(dtype)
        df = DisplacementField.generate(shape,
                                        approach="affine_simple",
                                        rotation=np.pi / 10)

        all_results = [
            df.warp_annotation(img, approach=x)
            for x in SUPPORTED_APPROACHES_ANNOTATIONS
        ]

        for i in range(len(all_results) - 1):
            assert np.array_equal(all_results[i], all_results[i + 1])