Пример #1
0
def test_ndim_paint():
    test_array = np.zeros((5, 6, 7, 8), dtype=int)
    layer = Labels(test_array)
    layer.n_edit_dimensions = 3
    with pytest.warns(FutureWarning):
        layer.brush_shape = 'circle'
    layer.brush_size = 2  # equivalent to 18-connected 3D neighborhood
    layer.paint((1, 1, 1, 1), 1)

    assert np.sum(layer.data) == 19  # 18 + center
    assert not np.any(layer.data[0]) and not np.any(layer.data[2:])

    layer.n_edit_dimensions = 2  # 3x3 square
    layer._dims_order = [1, 2, 0, 3]
    layer.paint((4, 5, 6, 7), 8)
    assert len(np.flatnonzero(layer.data == 8)) == 4  # 2D square is in corner
    np.testing.assert_array_equal(
        test_array[:, 5, 6, :],
        np.array([
            [0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 8, 8],
            [0, 0, 0, 0, 0, 0, 8, 8],
        ]),
    )
Пример #2
0
def test_n_edit_dimensions():
    """Test changing the number of editable dimensions."""
    np.random.seed(0)
    data = np.random.randint(20, size=(5, 10, 15))
    layer = Labels(data)
    layer.n_edit_dimensions = 2
    with pytest.warns(FutureWarning):
        assert layer.n_dimensional is False
    layer.n_edit_dimensions = 3
    with pytest.warns(FutureWarning):
        assert layer.n_dimensional is True
Пример #3
0
def test_fill_tensorstore():
    labels = np.zeros((5, 7, 8, 9), dtype=int)
    labels[1, 2:4, 4:6, 4:6] = 1
    labels[1, 3:5, 5:7, 6:8] = 2
    labels[2, 3:5, 5:7, 6:8] = 3
    with TemporaryDirectory(suffix='.zarr') as fout:
        labels_temp = zarr.open(
            fout,
            mode='w',
            shape=labels.shape,
            dtype=np.uint32,
            chunks=(1, 1, 8, 9),
        )
        labels_temp[:] = labels
        labels_ts_spec = {
            'driver': 'zarr',
            'kvstore': {
                'driver': 'file',
                'path': fout
            },
            'path': '',
            'metadata': {
                'dtype': labels_temp.dtype.str,
                'order': labels_temp.order,
                'shape': labels.shape,
            },
        }
        data = ts.open(labels_ts_spec, create=False, open=True).result()
        layer = Labels(data)
        layer.n_edit_dimensions = 3
        layer.fill((1, 4, 6, 7), 4)
        modified_labels = np.where(labels == 2, 4, labels)
        np.testing.assert_array_equal(modified_labels, np.asarray(data))
Пример #4
0
def test_undo_redo(
    brush_shape,
    brush_size,
    mode,
    selected_label,
    preserve_labels,
    n_dimensional,
):
    blobs = data.binary_blobs(length=64, volume_fraction=0.3, n_dim=3)
    layer = Labels(blobs)
    data_history = [blobs.copy()]
    with pytest.warns(FutureWarning):
        layer.brush_shape = brush_shape
    layer.brush_size = brush_size
    layer.mode = mode
    layer.selected_label = selected_label
    layer.preserve_labels = preserve_labels
    layer.n_edit_dimensions = 3 if n_dimensional else 2
    coord = np.random.random((3, )) * (np.array(blobs.shape) - 1)
    while layer.data[tuple(coord.astype(int))] == 0 and np.any(layer.data):
        coord = np.random.random((3, )) * (np.array(blobs.shape) - 1)
    if layer.mode == 'fill':
        layer.fill(coord, layer.selected_label)
    if layer.mode == 'erase':
        layer.paint(coord, 0)
    if layer.mode == 'paint':
        layer.paint(coord, layer.selected_label)
    data_history.append(np.copy(layer.data))
    layer.undo()
    np.testing.assert_array_equal(layer.data, data_history[0])
    layer.redo()
    np.testing.assert_array_equal(layer.data, data_history[1])
Пример #5
0
def test_n_edit_dimensions():
    """Test changing the number of editable dimensions."""
    np.random.seed(0)
    data = np.random.randint(20, size=(5, 10, 15))
    layer = Labels(data)
    layer.n_edit_dimensions = 2
    layer.n_edit_dimensions = 3
Пример #6
0
def test_ndim_fill():
    test_array = np.zeros((5, 5, 5, 5), dtype=int)

    test_array[:, 1:3, 1:3, 1:3] = 1

    layer = Labels(test_array)
    layer.n_edit_dimensions = 3

    layer.fill((0, 1, 1, 1), 2)

    np.testing.assert_equal(layer.data[0, 1:3, 1:3, 1:3], 2)
    np.testing.assert_equal(layer.data[1, 1:3, 1:3, 1:3], 1)

    layer.n_edit_dimensions = 4

    layer.fill((1, 1, 1, 1), 3)

    np.testing.assert_equal(layer.data[0, 1:3, 1:3, 1:3], 2)
    np.testing.assert_equal(layer.data[1:, 1:3, 1:3, 1:3], 3)
Пример #7
0
def test_paint_3d_negative_scale(scale):
    labels = np.zeros((3, 5, 11, 11), dtype=int)
    labels_layer = Labels(labels,
                          scale=(1, ) + scale,
                          translate=(-200, 100, 100))
    labels_layer.n_edit_dimensions = 3
    labels_layer.brush_size = 8
    labels_layer.paint((1, 2, 5, 5), 1)
    np.testing.assert_array_equal(np.sum(labels_layer.data, axis=(1, 2, 3)),
                                  [0, 95, 0])
Пример #8
0
def test_fill_nD_all(MouseEvent):
    """Test filling label nD."""
    data = np.ones((20, 20, 20), dtype=np.int32)
    data[:5, :5, :5] = 2
    data[0, 8:10, 8:10] = 2
    data[-5:, -5:, -5:] = 3
    layer = Labels(data)
    assert np.unique(layer.data[:5, :5, :5]) == 2
    assert np.unique(layer.data[-5:, -5:, -5:]) == 3
    assert np.unique(layer.data[:5, -5:, -5:]) == 1
    assert np.unique(layer.data[-5:, :5, -5:]) == 1
    assert np.unique(layer.data[0, 8:10, 8:10]) == 2

    layer.n_edit_dimensions = 3
    layer.mode = 'fill'
    layer.selected_label = 4

    # Simulate click
    event = ReadOnlyWrapper(
        MouseEvent(
            type='mouse_press',
            is_dragging=False,
            position=(0, 0, 0),
            view_direction=(1, 0, 0),
            dims_displayed=(0, 1),
            dims_point=(0, 0),
        )
    )
    mouse_press_callbacks(layer, event)
    assert np.unique(layer.data[:5, :5, :5]) == 4
    assert np.unique(layer.data[-5:, -5:, -5:]) == 3
    assert np.unique(layer.data[:5, -5:, -5:]) == 1
    assert np.unique(layer.data[-5:, :5, -5:]) == 1
    assert np.unique(layer.data[0, 8:10, 8:10]) == 2

    layer.selected_label = 5

    # Simulate click
    event = ReadOnlyWrapper(
        MouseEvent(
            type='mouse_press',
            is_dragging=False,
            position=(0, 19, 19),
            view_direction=(1, 0, 0),
            dims_displayed=(0, 1),
            dims_point=(0, 0, 0),
        )
    )
    mouse_press_callbacks(layer, event)
    assert np.unique(layer.data[:5, :5, :5]) == 4
    assert np.unique(layer.data[-5:, -5:, -5:]) == 3
    assert np.unique(layer.data[:5, -5:, -5:]) == 5
    assert np.unique(layer.data[-5:, :5, -5:]) == 5
    assert np.unique(layer.data[0, 8:10, 8:10]) == 2
Пример #9
0
def test_paint_3d():
    """Test painting labels with circle brush on 3D image."""
    data = np.zeros((30, 40, 40), dtype=np.uint32)
    layer = Labels(data)
    layer.brush_size = 12
    layer.mode = 'paint'

    # Paint in 2D
    layer.paint((10, 10, 10), 3)

    # Paint in 3D
    layer.n_edit_dimensions = 3
    layer.paint((10, 25, 10), 4)

    # Paint in 3D, preserve labels
    layer.n_edit_dimensions = 3
    layer.preserve_labels = True
    layer.paint((10, 15, 15), 5)

    assert np.sum(layer.data[4:17, 4:17, 4:17] == 3) == 137
    assert np.sum(layer.data[4:17, 19:32, 4:17] == 4) == 1189
    assert np.sum(layer.data[4:17, 9:32, 9:32] == 5) == 1103
Пример #10
0
def test_paint_3d(brush_shape, expected_sum):
    """Test painting labels with circle/square brush on 3D image."""
    data = np.zeros((30, 40, 40), dtype=np.uint32)
    layer = Labels(data)
    layer.brush_size = 12
    with pytest.warns(FutureWarning):
        layer.brush_shape = brush_shape
    layer.mode = 'paint'

    # Paint in 2D
    layer.paint((10, 10, 10), 3)

    # Paint in 3D
    layer.n_edit_dimensions = 3
    layer.paint((10, 25, 10), 4)

    # Paint in 3D, preserve labels
    layer.n_edit_dimensions = 3
    layer.preserve_labels = True
    layer.paint((10, 15, 15), 5)

    assert np.sum(layer.data[4:17, 4:17, 4:17] == 3) == expected_sum[0]
    assert np.sum(layer.data[4:17, 19:32, 4:17] == 4) == expected_sum[1]
    assert np.sum(layer.data[4:17, 9:32, 9:32] == 5) == expected_sum[2]
Пример #11
0
def test_paint_3d(MouseEvent):
    """Test filling label nD."""
    data = np.zeros((21, 21, 21), dtype=np.int32)
    data[10, 10, 10] = 1
    layer = Labels(data)
    layer._slice_dims(point=(0, 0, 0), ndisplay=3)

    layer.n_edit_dimensions = 3
    layer.mode = 'paint'
    layer.selected_label = 4
    layer.brush_size = 3

    # Simulate click
    event = ReadOnlyWrapper(
        MouseEvent(
            type='mouse_press',
            is_dragging=False,
            position=(0.1, 0, 0),
            view_direction=np.full(3, np.sqrt(3)),
            dims_displayed=(0, 1, 2),
            dims_point=(0, 0, 0),
        )
    )
    mouse_press_callbacks(layer, event)
    np.testing.assert_array_equal(np.unique(layer.data), [0, 4])
    num_filled = np.bincount(layer.data.ravel())[4]
    assert num_filled > 1

    layer.mode = 'erase'

    # Simulate click
    event = ReadOnlyWrapper(
        MouseEvent(
            type='mouse_press',
            is_dragging=False,
            position=(0, 10, 10),
            view_direction=(1, 0, 0),
            dims_displayed=(0, 1, 2),
            dims_point=(0, 0, 0),
        )
    )
    mouse_press_callbacks(layer, event)

    new_num_filled = np.bincount(layer.data.ravel())[4]
    assert new_num_filled < num_filled
Пример #12
0
def test_erase_3d_undo_empty(MouseEvent):
    """Nothing should be added to undo queue when clicks fall outside data."""
    data = np.zeros((20, 20, 20), dtype=np.int32)
    data[10, :, :] = 1
    layer = Labels(data)
    layer.brush_size = 5
    layer.mode = 'erase'
    layer._slice_dims(point=(0, 0, 0), ndisplay=3)
    layer.n_edit_dimensions = 3

    # Simulate click, outside data
    event = ReadOnlyWrapper(
        MouseEvent(
            type='mouse_press',
            is_dragging=False,
            position=(-1, -1, -1),
            view_direction=(1, 0, 0),
            dims_displayed=(0, 1, 2),
            dims_point=(0, 0, 0),
        )
    )
    mouse_press_callbacks(layer, event)

    # Simulate release
    event = ReadOnlyWrapper(
        MouseEvent(
            type='mouse_release',
            is_dragging=False,
            position=(-1, -1, -1),
            view_direction=(1, 0, 0),
            dims_displayed=(0, 1, 2),
            dims_point=(0, 0, 0),
        )
    )
    mouse_release_callbacks(layer, event)

    # Undo queue should be empty
    assert len(layer._undo_history) == 0
Пример #13
0
def test_erase_3d_undo(MouseEvent):
    """Test erasing labels in 3D then undoing the erase.

    Specifically, this test checks that undo is correctly filled even
    when a click and drag starts outside of the data volume.
    """
    data = np.zeros((20, 20, 20), dtype=np.int32)
    data[10, :, :] = 1
    layer = Labels(data)
    layer.brush_size = 5
    layer.mode = 'erase'
    layer._slice_dims(point=(0, 0, 0), ndisplay=3)
    layer.n_edit_dimensions = 3

    # Simulate click
    event = ReadOnlyWrapper(
        MouseEvent(
            type='mouse_press',
            is_dragging=False,
            position=(-1, -1, -1),
            view_direction=(1, 0, 0),
            dims_displayed=(0, 1, 2),
            dims_point=(0, 0, 0),
        )
    )
    mouse_press_callbacks(layer, event)

    # Simulate drag. Note: we need to include top left and bottom right in the
    # drag or there are no coordinates to interpolate
    event = ReadOnlyWrapper(
        MouseEvent(
            type='mouse_move',
            is_dragging=True,
            position=(-1, 0.1, 0.1),
            view_direction=(1, 0, 0),
            dims_displayed=(0, 1, 2),
            dims_point=(0, 0, 0),
        )
    )
    mouse_move_callbacks(layer, event)
    event = ReadOnlyWrapper(
        MouseEvent(
            type='mouse_move',
            is_dragging=True,
            position=(-1, 18.9, 18.9),
            view_direction=(1, 0, 0),
            dims_displayed=(0, 1, 2),
            dims_point=(0, 0, 0),
        )
    )
    mouse_move_callbacks(layer, event)

    # Simulate release
    event = ReadOnlyWrapper(
        MouseEvent(
            type='mouse_release',
            is_dragging=False,
            position=(-1, 21, 21),
            view_direction=(1, 0, 0),
            dims_displayed=(0, 1, 2),
            dims_point=(0, 0, 0),
        )
    )
    mouse_release_callbacks(layer, event)

    # Erasing goes from (-1, -1, -1) to (-1, 21, 21), should split the labels
    # into two sections. Undoing should work and reunite the labels to one
    # square
    assert ndi.label(layer.data)[1] == 2
    layer.undo()
    assert ndi.label(layer.data)[1] == 1