1import numpy as np 2import pytest 3from skimage.morphology import remove_small_objects, remove_small_holes 4 5from skimage._shared import testing 6from skimage._shared.testing import assert_array_equal, assert_equal 7from skimage._shared._warnings import expected_warnings 8 9 10test_image = np.array([[0, 0, 0, 1, 0], 11 [1, 1, 1, 0, 0], 12 [1, 1, 1, 0, 1]], bool) 13 14 15def test_one_connectivity(): 16 expected = np.array([[0, 0, 0, 0, 0], 17 [1, 1, 1, 0, 0], 18 [1, 1, 1, 0, 0]], bool) 19 observed = remove_small_objects(test_image, min_size=6) 20 assert_array_equal(observed, expected) 21 22 23def test_two_connectivity(): 24 expected = np.array([[0, 0, 0, 1, 0], 25 [1, 1, 1, 0, 0], 26 [1, 1, 1, 0, 0]], bool) 27 observed = remove_small_objects(test_image, min_size=7, connectivity=2) 28 assert_array_equal(observed, expected) 29 30 31def test_in_place(): 32 image = test_image.copy() 33 with expected_warnings(["in_place argument is deprecated"]): 34 observed = remove_small_objects(image, min_size=6, in_place=True) 35 assert_equal(observed is image, True, 36 "remove_small_objects in_place argument failed.") 37 38 39@pytest.mark.parametrize("in_dtype", [bool, int, np.int32]) 40@pytest.mark.parametrize("out_dtype", [bool, int, np.int32]) 41def test_out(in_dtype, out_dtype): 42 image = test_image.astype(in_dtype, copy=True) 43 expected_out = np.empty_like(test_image, dtype=out_dtype) 44 45 if out_dtype != bool: 46 # object with only 1 label will warn on non-bool output dtype 47 exp_warn = ["Only one label was provided"] 48 else: 49 exp_warn = [] 50 51 with expected_warnings(exp_warn): 52 out = remove_small_objects(image, min_size=6, out=expected_out) 53 54 assert out is expected_out 55 56 57def test_labeled_image(): 58 labeled_image = np.array([[2, 2, 2, 0, 1], 59 [2, 2, 2, 0, 1], 60 [2, 0, 0, 0, 0], 61 [0, 0, 3, 3, 3]], dtype=int) 62 expected = np.array([[2, 2, 2, 0, 0], 63 [2, 2, 2, 0, 0], 64 [2, 0, 0, 0, 0], 65 [0, 0, 3, 3, 3]], dtype=int) 66 observed = remove_small_objects(labeled_image, min_size=3) 67 assert_array_equal(observed, expected) 68 69 70def test_uint_image(): 71 labeled_image = np.array([[2, 2, 2, 0, 1], 72 [2, 2, 2, 0, 1], 73 [2, 0, 0, 0, 0], 74 [0, 0, 3, 3, 3]], dtype=np.uint8) 75 expected = np.array([[2, 2, 2, 0, 0], 76 [2, 2, 2, 0, 0], 77 [2, 0, 0, 0, 0], 78 [0, 0, 3, 3, 3]], dtype=np.uint8) 79 observed = remove_small_objects(labeled_image, min_size=3) 80 assert_array_equal(observed, expected) 81 82 83def test_single_label_warning(): 84 image = np.array([[0, 0, 0, 1, 0], 85 [1, 1, 1, 0, 0], 86 [1, 1, 1, 0, 0]], int) 87 with expected_warnings(['use a boolean array?']): 88 remove_small_objects(image, min_size=6) 89 90 91def test_float_input(): 92 float_test = np.random.rand(5, 5) 93 with testing.raises(TypeError): 94 remove_small_objects(float_test) 95 96 97def test_negative_input(): 98 negative_int = np.random.randint(-4, -1, size=(5, 5)) 99 with testing.raises(ValueError): 100 remove_small_objects(negative_int) 101 102 103test_holes_image = np.array([[0, 0, 0, 0, 0, 0, 1, 0, 0, 0], 104 [0, 1, 1, 1, 1, 1, 0, 0, 0, 0], 105 [0, 1, 0, 0, 1, 1, 0, 0, 0, 0], 106 [0, 1, 1, 1, 0, 1, 0, 0, 0, 0], 107 [0, 1, 1, 1, 1, 1, 0, 0, 0, 0], 108 [0, 0, 0, 0, 0, 0, 0, 1, 1, 1], 109 [0, 0, 0, 0, 0, 0, 0, 1, 0, 1], 110 [0, 0, 0, 0, 0, 0, 0, 1, 1, 1]], bool) 111 112 113def test_one_connectivity_holes(): 114 expected = np.array([[0, 0, 0, 0, 0, 0, 1, 0, 0, 0], 115 [0, 1, 1, 1, 1, 1, 0, 0, 0, 0], 116 [0, 1, 1, 1, 1, 1, 0, 0, 0, 0], 117 [0, 1, 1, 1, 1, 1, 0, 0, 0, 0], 118 [0, 1, 1, 1, 1, 1, 0, 0, 0, 0], 119 [0, 0, 0, 0, 0, 0, 0, 1, 1, 1], 120 [0, 0, 0, 0, 0, 0, 0, 1, 1, 1], 121 [0, 0, 0, 0, 0, 0, 0, 1, 1, 1]], bool) 122 observed = remove_small_holes(test_holes_image, area_threshold=3) 123 assert_array_equal(observed, expected) 124 125 126def test_two_connectivity_holes(): 127 expected = np.array([[0, 0, 0, 0, 0, 0, 1, 0, 0, 0], 128 [0, 1, 1, 1, 1, 1, 0, 0, 0, 0], 129 [0, 1, 0, 0, 1, 1, 0, 0, 0, 0], 130 [0, 1, 1, 1, 0, 1, 0, 0, 0, 0], 131 [0, 1, 1, 1, 1, 1, 0, 0, 0, 0], 132 [0, 0, 0, 0, 0, 0, 0, 1, 1, 1], 133 [0, 0, 0, 0, 0, 0, 0, 1, 1, 1], 134 [0, 0, 0, 0, 0, 0, 0, 1, 1, 1]], bool) 135 observed = remove_small_holes(test_holes_image, area_threshold=3, 136 connectivity=2) 137 assert_array_equal(observed, expected) 138 139 140def test_in_place_holes(): 141 image = test_holes_image.copy() 142 with expected_warnings(["in_place argument is deprecated"]): 143 observed = remove_small_holes(image, area_threshold=3, in_place=True) 144 assert_equal(observed is image, True, 145 "remove_small_holes in_place argument failed.") 146 147 148def test_out_remove_small_holes(): 149 image = test_holes_image.copy() 150 expected_out = np.empty_like(image) 151 out = remove_small_holes(image, area_threshold=3, out=expected_out) 152 153 assert out is expected_out 154 155 156def test_non_bool_out(): 157 image = test_holes_image.copy() 158 expected_out = np.empty_like(image, dtype=int) 159 with testing.raises(TypeError): 160 remove_small_holes(image, area_threshold=3, out=expected_out) 161 162 163def test_labeled_image_holes(): 164 labeled_holes_image = np.array([[0, 0, 0, 0, 0, 0, 1, 0, 0, 0], 165 [0, 1, 1, 1, 1, 1, 0, 0, 0, 0], 166 [0, 1, 0, 0, 1, 1, 0, 0, 0, 0], 167 [0, 1, 1, 1, 0, 1, 0, 0, 0, 0], 168 [0, 1, 1, 1, 1, 1, 0, 0, 0, 0], 169 [0, 0, 0, 0, 0, 0, 0, 2, 2, 2], 170 [0, 0, 0, 0, 0, 0, 0, 2, 0, 2], 171 [0, 0, 0, 0, 0, 0, 0, 2, 2, 2]], 172 dtype=int) 173 expected = np.array([[0, 0, 0, 0, 0, 0, 1, 0, 0, 0], 174 [0, 1, 1, 1, 1, 1, 0, 0, 0, 0], 175 [0, 1, 1, 1, 1, 1, 0, 0, 0, 0], 176 [0, 1, 1, 1, 1, 1, 0, 0, 0, 0], 177 [0, 1, 1, 1, 1, 1, 0, 0, 0, 0], 178 [0, 0, 0, 0, 0, 0, 0, 1, 1, 1], 179 [0, 0, 0, 0, 0, 0, 0, 1, 1, 1], 180 [0, 0, 0, 0, 0, 0, 0, 1, 1, 1]], dtype=bool) 181 with expected_warnings(['returned as a boolean array']): 182 observed = remove_small_holes(labeled_holes_image, area_threshold=3) 183 assert_array_equal(observed, expected) 184 185 186def test_uint_image_holes(): 187 labeled_holes_image = np.array([[0, 0, 0, 0, 0, 0, 1, 0, 0, 0], 188 [0, 1, 1, 1, 1, 1, 0, 0, 0, 0], 189 [0, 1, 0, 0, 1, 1, 0, 0, 0, 0], 190 [0, 1, 1, 1, 0, 1, 0, 0, 0, 0], 191 [0, 1, 1, 1, 1, 1, 0, 0, 0, 0], 192 [0, 0, 0, 0, 0, 0, 0, 2, 2, 2], 193 [0, 0, 0, 0, 0, 0, 0, 2, 0, 2], 194 [0, 0, 0, 0, 0, 0, 0, 2, 2, 2]], 195 dtype=np.uint8) 196 expected = np.array([[0, 0, 0, 0, 0, 0, 1, 0, 0, 0], 197 [0, 1, 1, 1, 1, 1, 0, 0, 0, 0], 198 [0, 1, 1, 1, 1, 1, 0, 0, 0, 0], 199 [0, 1, 1, 1, 1, 1, 0, 0, 0, 0], 200 [0, 1, 1, 1, 1, 1, 0, 0, 0, 0], 201 [0, 0, 0, 0, 0, 0, 0, 1, 1, 1], 202 [0, 0, 0, 0, 0, 0, 0, 1, 1, 1], 203 [0, 0, 0, 0, 0, 0, 0, 1, 1, 1]], dtype=bool) 204 with expected_warnings(['returned as a boolean array']): 205 observed = remove_small_holes(labeled_holes_image, area_threshold=3) 206 assert_array_equal(observed, expected) 207 208 209def test_label_warning_holes(): 210 labeled_holes_image = np.array([[0, 0, 0, 0, 0, 0, 1, 0, 0, 0], 211 [0, 1, 1, 1, 1, 1, 0, 0, 0, 0], 212 [0, 1, 0, 0, 1, 1, 0, 0, 0, 0], 213 [0, 1, 1, 1, 0, 1, 0, 0, 0, 0], 214 [0, 1, 1, 1, 1, 1, 0, 0, 0, 0], 215 [0, 0, 0, 0, 0, 0, 0, 2, 2, 2], 216 [0, 0, 0, 0, 0, 0, 0, 2, 0, 2], 217 [0, 0, 0, 0, 0, 0, 0, 2, 2, 2]], 218 dtype=int) 219 with expected_warnings(['use a boolean array?']): 220 remove_small_holes(labeled_holes_image, area_threshold=3) 221 remove_small_holes(labeled_holes_image.astype(bool), area_threshold=3) 222 223 224def test_float_input_holes(): 225 float_test = np.random.rand(5, 5) 226 with testing.raises(TypeError): 227 remove_small_holes(float_test) 228