import numpy as np import pytest from skimage.morphology import remove_small_objects, remove_small_holes from skimage._shared import testing from skimage._shared.testing import assert_array_equal, assert_equal from skimage._shared._warnings import expected_warnings test_image = np.array([[0, 0, 0, 1, 0], [1, 1, 1, 0, 0], [1, 1, 1, 0, 1]], bool) def test_one_connectivity(): expected = np.array([[0, 0, 0, 0, 0], [1, 1, 1, 0, 0], [1, 1, 1, 0, 0]], bool) observed = remove_small_objects(test_image, min_size=6) assert_array_equal(observed, expected) def test_two_connectivity(): expected = np.array([[0, 0, 0, 1, 0], [1, 1, 1, 0, 0], [1, 1, 1, 0, 0]], bool) observed = remove_small_objects(test_image, min_size=7, connectivity=2) assert_array_equal(observed, expected) def test_in_place(): image = test_image.copy() with expected_warnings(["in_place argument is deprecated"]): observed = remove_small_objects(image, min_size=6, in_place=True) assert_equal(observed is image, True, "remove_small_objects in_place argument failed.") @pytest.mark.parametrize("in_dtype", [bool, int, np.int32]) @pytest.mark.parametrize("out_dtype", [bool, int, np.int32]) def test_out(in_dtype, out_dtype): image = test_image.astype(in_dtype, copy=True) expected_out = np.empty_like(test_image, dtype=out_dtype) if out_dtype != bool: # object with only 1 label will warn on non-bool output dtype exp_warn = ["Only one label was provided"] else: exp_warn = [] with expected_warnings(exp_warn): out = remove_small_objects(image, min_size=6, out=expected_out) assert out is expected_out def test_labeled_image(): labeled_image = np.array([[2, 2, 2, 0, 1], [2, 2, 2, 0, 1], [2, 0, 0, 0, 0], [0, 0, 3, 3, 3]], dtype=int) expected = np.array([[2, 2, 2, 0, 0], [2, 2, 2, 0, 0], [2, 0, 0, 0, 0], [0, 0, 3, 3, 3]], dtype=int) observed = remove_small_objects(labeled_image, min_size=3) assert_array_equal(observed, expected) def test_uint_image(): labeled_image = np.array([[2, 2, 2, 0, 1], [2, 2, 2, 0, 1], [2, 0, 0, 0, 0], [0, 0, 3, 3, 3]], dtype=np.uint8) expected = np.array([[2, 2, 2, 0, 0], [2, 2, 2, 0, 0], [2, 0, 0, 0, 0], [0, 0, 3, 3, 3]], dtype=np.uint8) observed = remove_small_objects(labeled_image, min_size=3) assert_array_equal(observed, expected) def test_single_label_warning(): image = np.array([[0, 0, 0, 1, 0], [1, 1, 1, 0, 0], [1, 1, 1, 0, 0]], int) with expected_warnings(['use a boolean array?']): remove_small_objects(image, min_size=6) def test_float_input(): float_test = np.random.rand(5, 5) with testing.raises(TypeError): remove_small_objects(float_test) def test_negative_input(): negative_int = np.random.randint(-4, -1, size=(5, 5)) with testing.raises(ValueError): remove_small_objects(negative_int) test_holes_image = np.array([[0, 0, 0, 0, 0, 0, 1, 0, 0, 0], [0, 1, 1, 1, 1, 1, 0, 0, 0, 0], [0, 1, 0, 0, 1, 1, 0, 0, 0, 0], [0, 1, 1, 1, 0, 1, 0, 0, 0, 0], [0, 1, 1, 1, 1, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 1, 0, 1], [0, 0, 0, 0, 0, 0, 0, 1, 1, 1]], bool) def test_one_connectivity_holes(): expected = np.array([[0, 0, 0, 0, 0, 0, 1, 0, 0, 0], [0, 1, 1, 1, 1, 1, 0, 0, 0, 0], [0, 1, 1, 1, 1, 1, 0, 0, 0, 0], [0, 1, 1, 1, 1, 1, 0, 0, 0, 0], [0, 1, 1, 1, 1, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 1, 1, 1]], bool) observed = remove_small_holes(test_holes_image, area_threshold=3) assert_array_equal(observed, expected) def test_two_connectivity_holes(): expected = np.array([[0, 0, 0, 0, 0, 0, 1, 0, 0, 0], [0, 1, 1, 1, 1, 1, 0, 0, 0, 0], [0, 1, 0, 0, 1, 1, 0, 0, 0, 0], [0, 1, 1, 1, 0, 1, 0, 0, 0, 0], [0, 1, 1, 1, 1, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 1, 1, 1]], bool) observed = remove_small_holes(test_holes_image, area_threshold=3, connectivity=2) assert_array_equal(observed, expected) def test_in_place_holes(): image = test_holes_image.copy() with expected_warnings(["in_place argument is deprecated"]): observed = remove_small_holes(image, area_threshold=3, in_place=True) assert_equal(observed is image, True, "remove_small_holes in_place argument failed.") def test_out_remove_small_holes(): image = test_holes_image.copy() expected_out = np.empty_like(image) out = remove_small_holes(image, area_threshold=3, out=expected_out) assert out is expected_out def test_non_bool_out(): image = test_holes_image.copy() expected_out = np.empty_like(image, dtype=int) with testing.raises(TypeError): remove_small_holes(image, area_threshold=3, out=expected_out) def test_labeled_image_holes(): labeled_holes_image = np.array([[0, 0, 0, 0, 0, 0, 1, 0, 0, 0], [0, 1, 1, 1, 1, 1, 0, 0, 0, 0], [0, 1, 0, 0, 1, 1, 0, 0, 0, 0], [0, 1, 1, 1, 0, 1, 0, 0, 0, 0], [0, 1, 1, 1, 1, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 2, 2, 2], [0, 0, 0, 0, 0, 0, 0, 2, 0, 2], [0, 0, 0, 0, 0, 0, 0, 2, 2, 2]], dtype=int) expected = np.array([[0, 0, 0, 0, 0, 0, 1, 0, 0, 0], [0, 1, 1, 1, 1, 1, 0, 0, 0, 0], [0, 1, 1, 1, 1, 1, 0, 0, 0, 0], [0, 1, 1, 1, 1, 1, 0, 0, 0, 0], [0, 1, 1, 1, 1, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 1, 1, 1]], dtype=bool) with expected_warnings(['returned as a boolean array']): observed = remove_small_holes(labeled_holes_image, area_threshold=3) assert_array_equal(observed, expected) def test_uint_image_holes(): labeled_holes_image = np.array([[0, 0, 0, 0, 0, 0, 1, 0, 0, 0], [0, 1, 1, 1, 1, 1, 0, 0, 0, 0], [0, 1, 0, 0, 1, 1, 0, 0, 0, 0], [0, 1, 1, 1, 0, 1, 0, 0, 0, 0], [0, 1, 1, 1, 1, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 2, 2, 2], [0, 0, 0, 0, 0, 0, 0, 2, 0, 2], [0, 0, 0, 0, 0, 0, 0, 2, 2, 2]], dtype=np.uint8) expected = np.array([[0, 0, 0, 0, 0, 0, 1, 0, 0, 0], [0, 1, 1, 1, 1, 1, 0, 0, 0, 0], [0, 1, 1, 1, 1, 1, 0, 0, 0, 0], [0, 1, 1, 1, 1, 1, 0, 0, 0, 0], [0, 1, 1, 1, 1, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 1, 1, 1]], dtype=bool) with expected_warnings(['returned as a boolean array']): observed = remove_small_holes(labeled_holes_image, area_threshold=3) assert_array_equal(observed, expected) def test_label_warning_holes(): labeled_holes_image = np.array([[0, 0, 0, 0, 0, 0, 1, 0, 0, 0], [0, 1, 1, 1, 1, 1, 0, 0, 0, 0], [0, 1, 0, 0, 1, 1, 0, 0, 0, 0], [0, 1, 1, 1, 0, 1, 0, 0, 0, 0], [0, 1, 1, 1, 1, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 2, 2, 2], [0, 0, 0, 0, 0, 0, 0, 2, 0, 2], [0, 0, 0, 0, 0, 0, 0, 2, 2, 2]], dtype=int) with expected_warnings(['use a boolean array?']): remove_small_holes(labeled_holes_image, area_threshold=3) remove_small_holes(labeled_holes_image.astype(bool), area_threshold=3) def test_float_input_holes(): float_test = np.random.rand(5, 5) with testing.raises(TypeError): remove_small_holes(float_test)