def run(self, ips, imgs, para=None): flood_fill(imgs, para['seed'], para['color'], connectivity=para['conn'], tolerance=para['tor'], inplace=True)
def test_selem(): # Basic tests for nonstandard structuring elements selem = np.array([[0, 1, 1], [0, 1, 1], [0, 0, 0]]) # Cannot grow left or down output = flood_fill(np.zeros((5, 6), dtype=np.uint8), (3, 1), 255, selem=selem) expected = np.array([[0, 255, 255, 255, 255, 255], [0, 255, 255, 255, 255, 255], [0, 255, 255, 255, 255, 255], [0, 255, 255, 255, 255, 255], [0, 0, 0, 0, 0, 0]], dtype=np.uint8) np.testing.assert_equal(output, expected) selem = np.array([[0, 0, 0], [1, 1, 0], [1, 1, 0]]) # Cannot grow right or up output = flood_fill(np.zeros((5, 6), dtype=np.uint8), (1, 4), 255, selem=selem) expected = np.array([[ 0, 0, 0, 0, 0, 0], [255, 255, 255, 255, 255, 0], [255, 255, 255, 255, 255, 0], [255, 255, 255, 255, 255, 0], [255, 255, 255, 255, 255, 0]], dtype=np.uint8) np.testing.assert_equal(output, expected)
def generateCosts(diffImg, mask): costsArr = np.ones_like(diffImg) row, col = mask.nonzero() c = (col.min(), col.max()) shape = mask.shape lbls = mask.copy().astype(np.uint8) cslice = slice(c[0], c[1] + 1) submask = np.ascontiguousarray(lbls[:, cslice]) submask = flood_fill(submask, (0, 0), 2) submask = flood_fill(submask, (shape[0] - 1, 0), 3) lbls[:, cslice] = submask upper = (lbls == 2).sub(axis=0).astype(np.float64) lower = (lbls == 3).sub(axis=0).astype(np.float64) ugood = np.abs(np.gradient(upper[cslice])) < 2.0 lgood = np.abs(np.gradient(lower[cslice])) < 2.0 costsUpper = np.ones_like(upper) costsLower = np.ones_like(lower) costsUpper[cslice][ugood] = upper[cslice].min() / np.maximum( upper[cslice][ugood], 1) costsLower[cslice][lgood] = lower[cslice].min() / np.maximim( lower[cslice][lgood], 1) vdist = mask.shape[0] costUpper = costsUpper[np.newaxis, :].repeat(vdist, axis=0) costLower = costsLower[np.newaxis, :].repeat(vdist, axis=0) costsArr[:, cslice] = costsUpper[:, cslice] * (lbls[:, cslice] == 2) costsArr[:, cslice] += costsLower[:, cslice] * (lbls[:, cslice] == 3) costsArr[mask] = diffImg[mask] return costsArr
def test_selem(): # Basic tests for nonstandard structuring elements selem = np.array([[0, 1, 1], [0, 1, 1], [0, 0, 0]]) # Cannot grow left or down output = flood_fill(np.zeros((5, 6), dtype=np.uint8), (3, 1), 255, selem=selem) expected = np.array( [[0, 255, 255, 255, 255, 255], [0, 255, 255, 255, 255, 255], [0, 255, 255, 255, 255, 255], [0, 255, 255, 255, 255, 255], [0, 0, 0, 0, 0, 0]], dtype=np.uint8) np.testing.assert_equal(output, expected) selem = np.array([[0, 0, 0], [1, 1, 0], [1, 1, 0]]) # Cannot grow right or up output = flood_fill(np.zeros((5, 6), dtype=np.uint8), (1, 4), 255, selem=selem) expected = np.array( [[0, 0, 0, 0, 0, 0], [255, 255, 255, 255, 255, 0], [255, 255, 255, 255, 255, 0], [255, 255, 255, 255, 255, 0], [255, 255, 255, 255, 255, 0]], dtype=np.uint8) np.testing.assert_equal(output, expected)
def removeAllHoles(self, img: np.ndarray, x: int = 0, y: int = 0): print('fill in empty spaces in objects...') tmp = np.array(img, np.uint8) original = tmp.copy() flood_fill(tmp, (x, y), 1, inplace=True) tmp = self.getInverse(tmp) return np.logical_or(tmp, original)
def __isolate_lung(self, seg): """ Segment the lung in the body :param seg: the segmentation of the human body :return: segmentation of lung """ # take only the parts that contain air cut_seg = np.zeros((seg.shape)) new_seg1 = np.zeros((seg.shape)) new_seg1[:, :, :] = 1 - seg[:, :, :] new_seg = binary_closing(np.copy(new_seg1), np.ones((3, 3, 3))) # delete air that is outside the body m_ax = (new_seg.shape[2] * 1) // 2 cut_seg[:, :, m_ax:] = np.copy(new_seg[:, :, m_ax:]) cut_seg[:, :, m_ax:] = flood_fill(cut_seg[:, :, m_ax:], (0, 0, 0), 2) cut_seg[:, :, m_ax:] = flood_fill(cut_seg[:, :, m_ax:], (cut_seg[:, :, m_ax:].shape[0] - 1, cut_seg[:, :, m_ax:].shape[1] - 1, 0), 3) new_seg[np.where((cut_seg == 2) | (cut_seg == 3))] = 0 reg_seg = np.copy(new_seg) new_seg[:, :, m_ax:] = self.__choose_largest_co_component( np.copy(reg_seg[:, :, m_ax:]), 1) new_seg[:, :, :m_ax] = 0 return new_seg
def test_inplace_noncontiguous(): image = np.array([[0, 0, 0, 0, 0, 0, 0], [0, 1, 1, 0, 2, 2, 0], [0, 1, 1, 0, 2, 2, 0], [1, 0, 0, 0, 0, 0, 3], [0, 1, 1, 1, 3, 3, 4]]) # Transpose is noncontiguous image2 = image[::2, ::2] flood_fill(image2, (0, 0), 5, in_place=True) # The inplace modified result expected2 = np.array([[5, 5, 5, 5], [5, 1, 2, 5], [5, 1, 3, 4]]) np.testing.assert_allclose(image2, expected2) # Projected back through the view, `image` also modified expected = np.array([[5, 0, 5, 0, 5, 0, 5], [0, 1, 1, 0, 2, 2, 0], [5, 1, 1, 0, 2, 2, 5], [1, 0, 0, 0, 0, 0, 3], [5, 1, 1, 1, 3, 3, 4]]) np.testing.assert_allclose(image, expected)
def test_footprint(): # Basic tests for nonstandard footprints footprint = np.array([[0, 1, 1], [0, 1, 1], [0, 0, 0]]) # Cannot grow left or down output = flood_fill(np.zeros((5, 6), dtype=np.uint8), (3, 1), 255, footprint=footprint) expected = np.array( [[0, 255, 255, 255, 255, 255], [0, 255, 255, 255, 255, 255], [0, 255, 255, 255, 255, 255], [0, 255, 255, 255, 255, 255], [0, 0, 0, 0, 0, 0]], dtype=np.uint8) np.testing.assert_equal(output, expected) footprint = np.array([[0, 0, 0], [1, 1, 0], [1, 1, 0]]) # Cannot grow right or up output = flood_fill(np.zeros((5, 6), dtype=np.uint8), (1, 4), 255, footprint=footprint) expected = np.array( [[0, 0, 0, 0, 0, 0], [255, 255, 255, 255, 255, 0], [255, 255, 255, 255, 255, 0], [255, 255, 255, 255, 255, 0], [255, 255, 255, 255, 255, 0]], dtype=np.uint8) np.testing.assert_equal(output, expected)
def test_non_adjacent_footprint(): # Basic tests for non-adjacent footprints footprint = np.array([[1, 0, 0, 0, 1], [0, 0, 0, 0, 0], [0, 0, 1, 0, 0], [0, 0, 0, 0, 0], [1, 0, 0, 0, 1]]) output = flood_fill(np.zeros((5, 6), dtype=np.uint8), (2, 3), 255, footprint=footprint) expected = np.array( [[0, 255, 0, 0, 0, 255], [0, 0, 0, 0, 0, 0], [0, 0, 0, 255, 0, 0], [0, 0, 0, 0, 0, 0], [0, 255, 0, 0, 0, 255]], dtype=np.uint8) np.testing.assert_equal(output, expected) footprint = np.array([[1, 1, 1, 1, 1], [1, 1, 1, 1, 1], [1, 1, 1, 1, 1], [1, 1, 1, 1, 1], [1, 1, 1, 1, 1]]) image = np.zeros((5, 10), dtype=np.uint8) image[:, (3, 7, 8)] = 100 output = flood_fill(image, (0, 0), 255, footprint=footprint) expected = np.array([[255, 255, 255, 100, 255, 255, 255, 100, 100, 0], [255, 255, 255, 100, 255, 255, 255, 100, 100, 0], [255, 255, 255, 100, 255, 255, 255, 100, 100, 0], [255, 255, 255, 100, 255, 255, 255, 100, 100, 0], [255, 255, 255, 100, 255, 255, 255, 100, 100, 0]], dtype=np.uint8) np.testing.assert_equal(output, expected)
def test_inplace_noncontiguous(): image = np.array([[0, 0, 0, 0, 0, 0, 0], [0, 1, 1, 0, 2, 2, 0], [0, 1, 1, 0, 2, 2, 0], [1, 0, 0, 0, 0, 0, 3], [0, 1, 1, 1, 3, 3, 4]]) # Transpose is noncontiguous image2 = image[::2, ::2] flood_fill(image2, (0, 0), 5, inplace=True) # The inplace modified result expected2 = np.array([[5, 5, 5, 5], [5, 1, 2, 5], [5, 1, 3, 4]]) np.testing.assert_allclose(image2, expected2) # Projected back through the view, `image` also modified expected = np.array([[5, 0, 5, 0, 5, 0, 5], [0, 1, 1, 0, 2, 2, 0], [5, 1, 1, 0, 2, 2, 5], [1, 0, 0, 0, 0, 0, 3], [5, 1, 1, 1, 3, 3, 4]]) np.testing.assert_allclose(image, expected)
def test_1d(): image = np.arange(11) expected = np.array([0, 1, -20, -20, -20, -20, -20, -20, -20, 9, 10]) output = flood_fill(image, 5, -20, tolerance=3) output2 = flood_fill(image, (5, ), -20, tolerance=3) np.testing.assert_equal(output, expected) np.testing.assert_equal(output, output2)
def test_1d(): image = np.arange(11) expected = np.array([0, 1, -20, -20, -20, -20, -20, -20, -20, 9, 10]) output = flood_fill(image, 5, -20, tolerance=3) output2 = flood_fill(image, (5,), -20, tolerance=3) np.testing.assert_equal(output, expected) np.testing.assert_equal(output, output2)
def test_inplace_int(): image = np.array([[0, 0, 0, 0, 0, 0, 0], [0, 1, 1, 0, 2, 2, 0], [0, 1, 1, 0, 2, 2, 0], [1, 0, 0, 0, 0, 0, 3], [0, 1, 1, 1, 3, 3, 4]]) flood_fill(image, (0, 0), 5, inplace=True) expected = np.array([[5, 5, 5, 5, 5, 5, 5], [5, 1, 1, 5, 2, 2, 5], [5, 1, 1, 5, 2, 2, 5], [1, 5, 5, 5, 5, 5, 3], [5, 1, 1, 1, 3, 3, 4]]) np.testing.assert_array_equal(image, expected)
def global_out_fill(img, r, c, color): img = img.reshape((img.shape + (1, ))[:3]) ori = np.ones(img.shape[:2], dtype=np.bool) for i in range(img.shape[2]): ori &= flood(img[:, :, i], (r, c), connectivity=2) filled = binary_fill_holes(ori) dilation = binary_dilation(ori) dilation ^= filled rs, cs = np.where(dilation) if len(rs) == 0: return msk = ((img == img[r, c]).min(axis=2)).astype(np.uint8) flood_fill(msk, (rs[0], cs[0]), 2, connectivity=2, inplace=True) img[msk == 2] = color
def test_inplace_float(): image = np.array( [[0, 0, 0, 0, 0, 0, 0], [0, 1, 1, 0, 2, 2, 0], [0, 1, 1, 0, 2, 2, 0], [1, 0, 0, 0, 0, 0, 3], [0, 1, 1, 1, 3, 3, 4]], dtype=np.float32) flood_fill(image, (0, 0), 5, inplace=True) expected = np.array( [[5., 5., 5., 5., 5., 5., 5.], [5., 1., 1., 5., 2., 2., 5.], [5., 1., 1., 5., 2., 2., 5.], [1., 5., 5., 5., 5., 5., 3.], [5., 1., 1., 1., 3., 3., 4.]], dtype=np.float32) np.testing.assert_allclose(image, expected)
def test_inplace_int_deprecated(): """This test is deprecated and will be removed in version 0.19.0. See #4248. """ image = np.array([[0, 0, 0, 0, 0, 0, 0], [0, 1, 1, 0, 2, 2, 0], [0, 1, 1, 0, 2, 2, 0], [1, 0, 0, 0, 0, 0, 3], [0, 1, 1, 1, 3, 3, 4]]) with expected_warnings(['The `inplace`']): flood_fill(image, (0, 0), 5, inplace=True) expected = np.array([[5, 5, 5, 5, 5, 5, 5], [5, 1, 1, 5, 2, 2, 5], [5, 1, 1, 5, 2, 2, 5], [1, 5, 5, 5, 5, 5, 3], [5, 1, 1, 1, 3, 3, 4]]) np.testing.assert_array_equal(image, expected)
def test_overrange_tolerance_int(): image = np.arange(256, dtype=np.uint8).reshape((8, 8, 4)) expected = np.zeros_like(image) output = flood_fill(image, (7, 7, 3), 0, tolerance=379) np.testing.assert_equal(output, expected)
def action_flood_contiguous(self, label, frame, x_location, y_location): """Flood fill a cell with a unique new label. Alternative to watershed for fixing duplicate labels of non-touching objects. """ img_ann = self.annotated[frame, ..., self.feature] old_label = label new_label = self.get_max_label() + 1 in_original = np.any(np.isin(img_ann, old_label)) filled_img_ann = flood_fill(img_ann, (int(y_location / self.scale_factor), int(x_location / self.scale_factor)), new_label) self.annotated[frame, ..., self.feature] = filled_img_ann in_modified = np.any(np.isin(filled_img_ann, old_label)) # update cell info dicts since labels are changing self.add_cell_info(add_label=new_label, frame=frame) if in_original and not in_modified: self.del_cell_info(del_label=old_label, frame=frame)
def action_flood(self, label, x_location, y_location): """ Floods the region at (x, y) with the label. Only floods diagonally connected pixels (connectivity == 2) when label != 0. Args: label (int): label to fill region with x_location (int): x coordinate of region to flood y_location (int): y coordinate of region to flood """ label = self.clean_label(label) img = self.frame[..., self.feature] # Rescale click location to corresponding location in label array hole_fill_seed = (int(y_location), int(x_location)) # Check current label old_label = img[hole_fill_seed] # Flood region with label # helps prevents hole fill from spilling into background connectivity = 1 if old_label == 0 else 2 flooded = flood_fill(img, hole_fill_seed, label, connectivity=connectivity) # Update cell info dicts label_in_original = np.any(np.isin(label, img)) label_in_flooded = np.any(np.isin(label, flooded)) old_label_in_flooded = np.any(np.isin(old_label, flooded)) if label != 0 and not label_in_original and label_in_flooded: self.add_cell_info(add_label=label, frame=self.frame_id) if old_label != 0 and not old_label_in_flooded: self.del_cell_info(del_label=old_label, frame=self.frame_id) self.frame[..., self.feature] = flooded self.y_changed = True
def test_overrange_tolerance_int(): image = np.arange(256, dtype=np.uint8).reshape((8, 8, 4)) expected = np.zeros_like(image) output = flood_fill(image, (7, 7, 3), 0, tolerance=379) np.testing.assert_equal(output, expected)
def test_inplace_int(): image = np.array([[0, 0, 0, 0, 0, 0, 0], [0, 1, 1, 0, 2, 2, 0], [0, 1, 1, 0, 2, 2, 0], [1, 0, 0, 0, 0, 0, 3], [0, 1, 1, 1, 3, 3, 4]]) flood_fill(image, (0, 0), 5, inplace=True) expected = np.array([[5, 5, 5, 5, 5, 5, 5], [5, 1, 1, 5, 2, 2, 5], [5, 1, 1, 5, 2, 2, 5], [1, 5, 5, 5, 5, 5, 3], [5, 1, 1, 1, 3, 3, 4]]) np.testing.assert_array_equal(image, expected)
def test_inplace_float(): image = np.array([[0, 0, 0, 0, 0, 0, 0], [0, 1, 1, 0, 2, 2, 0], [0, 1, 1, 0, 2, 2, 0], [1, 0, 0, 0, 0, 0, 3], [0, 1, 1, 1, 3, 3, 4]], dtype=np.float32) flood_fill(image, (0, 0), 5, inplace=True) expected = np.array([[5., 5., 5., 5., 5., 5., 5.], [5., 1., 1., 5., 2., 2., 5.], [5., 1., 1., 5., 2., 2., 5.], [1., 5., 5., 5., 5., 5., 3.], [5., 1., 1., 1., 3., 3., 4.]], dtype=np.float32) np.testing.assert_allclose(image, expected)
def load_horizontal_mask(ann_d, liver_mask, verbose_curve=True): shape = liver_mask.shape curve_dict = ann_d['Horizontal']['data'] l = liver_mask.any(axis=(1, 2)) liver_start, liver_stop = np.argmax(l), len(l) - np.argmax(l[::-1]) - 1 curve_start, curve_stop = np.array(sorted(map(int, curve_dict.keys())))[[0, -1]] curve_dict[str(liver_start)] = curve_dict[str(curve_start)] curve_dict[str(liver_stop)] = curve_dict[str(curve_stop)] curve_slices = interpolate_dict(curve_dict, shape[0], closed=False) mask = [] for curve_slice, liver_slice in zip(curve_slices, liver_mask): m_ = np.zeros_like(liver_slice) if not curve_slice.any(): mask.append(m_) continue curve_slice = extrapolate_first_and_last_segments_to_border( curve_slice, liver_slice.shape) m_ = flood_fill(m_ + 2 * plot_curve(curve_slice, liver_slice.shape), (0, 0), new_value=1, connectivity=1) == 1 # TODO: get zones for all image, not only for a liver m_ = (m_ + 1) * liver_slice if verbose_curve: m_[plot_curve(curve_slice, liver_slice.shape)] = -1 mask.append(m_) return np.stack(mask)
def test_neighbors(): # This test will only pass if the neighbors are exactly correct test = np.zeros((5, 7), dtype=np.float64) test[:, 3] = 100 expected = np.array([[0, 0, 0, 255, 0, 0, 0], [0, 0, 0, 255, 0, 0, 0], [0, 0, 0, 255, 0, 0, 0], [0, 0, 0, 255, 0, 0, 0], [0, 0, 0, 255, 0, 0, 0]]) output = flood_fill(test, (0, 3), 255) np.testing.assert_equal(output, expected) test[2] = 100 expected[2] = 255 output2 = flood_fill(test, (2, 3), 255) np.testing.assert_equal(output2, expected)
def test_empty_input(): # Test shortcut output = flood_fill(np.empty(0), (), 2) assert output.size == 0 # Boolean output type assert flood(np.empty(0), ()).dtype == np.bool # Maintain shape, even with zero size present assert flood(np.empty((20, 0, 4)), ()).shape == (20, 0, 4)
def test_inplace_float_deprecated(): """This test is deprecated and will be removed in version 0.19.0. See #4248. """ image = np.array( [[0, 0, 0, 0, 0, 0, 0], [0, 1, 1, 0, 2, 2, 0], [0, 1, 1, 0, 2, 2, 0], [1, 0, 0, 0, 0, 0, 3], [0, 1, 1, 1, 3, 3, 4]], dtype=np.float32) with expected_warnings(['The `inplace`']): flood_fill(image, (0, 0), 5, inplace=True) expected = np.array( [[5., 5., 5., 5., 5., 5., 5.], [5., 1., 1., 5., 2., 2., 5.], [5., 1., 1., 5., 2., 2., 5.], [1., 5., 5., 5., 5., 5., 3.], [5., 1., 1., 1., 3., 3., 4.]], dtype=np.float32) np.testing.assert_allclose(image, expected)
def test_empty_input(): # Test shortcut output = flood_fill(np.empty(0), (), 2) assert output.size == 0 # Boolean output type assert flood(np.empty(0), ()).dtype == np.bool # Maintain shape, even with zero size present assert flood(np.empty((20, 0, 4)), ()).shape == (20, 0, 4)
def test_neighbors(): # This test will only pass if the neighbors are exactly correct test = np.zeros((5, 7), dtype=np.float64) test[:, 3] = 100 expected = np.array([[0, 0, 0, 255, 0, 0, 0], [0, 0, 0, 255, 0, 0, 0], [0, 0, 0, 255, 0, 0, 0], [0, 0, 0, 255, 0, 0, 0], [0, 0, 0, 255, 0, 0, 0]]) output = flood_fill(test, (0, 3), 255) np.testing.assert_equal(output, expected) test[2] = 100 expected[2] = 255 output2 = flood_fill(test, (2, 3), 255) np.testing.assert_equal(output2, expected)
def test_overrange_tolerance_float(): max_value = np.finfo(np.float32).max image = np.random.uniform(size=(64, 64), low=-1., high=1.).astype( np.float32) image *= max_value expected = np.ones_like(image) output = flood_fill(image, (0, 1), 1., tolerance=max_value * 10) np.testing.assert_equal(output, expected)
def test_overrange_tolerance_float(): max_value = np.finfo(np.float32).max min_value = np.finfo(np.float32).min image = np.random.uniform(size=(64, 64), low=-1., high=1.).astype( np.float32) image *= max_value expected = np.ones_like(image) output = flood_fill(image, (0, 1), 1., tolerance=max_value * 10) np.testing.assert_equal(output, expected)
def test_wraparound(): # If the borders (or neighbors) aren't correctly accounted for, this fails, # because the algorithm uses an ravelled array. test = np.zeros((5, 7), dtype=np.float64) test[:, 3] = 100 expected = np.array([[-1., -1., -1., 100., 0., 0., 0.], [-1., -1., -1., 100., 0., 0., 0.], [-1., -1., -1., 100., 0., 0., 0.], [-1., -1., -1., 100., 0., 0., 0.], [-1., -1., -1., 100., 0., 0., 0.]]) np.testing.assert_equal(flood_fill(test, (0, 0), -1), expected)
def __isolate_lung(self, seg): """ :param seg: :return: """ cut_seg = np.zeros((seg.shape)) new_seg1 = np.zeros((seg.shape)) new_seg1[:, :, :] = 1 - seg[:, :, :] new_seg = binary_closing(np.copy(new_seg1), np.ones((3, 3, 3))) m_ax = (new_seg.shape[2] * 1) // 2 cut_seg[:,:,m_ax:] = np.copy(new_seg[:,:,m_ax:]) cut_seg[:,:,m_ax:] = flood_fill(cut_seg[:,:,m_ax:],(0, 0, 0), 2) cut_seg[:, :, m_ax:] = flood_fill(cut_seg[:, :, m_ax:], ( cut_seg[:, :, m_ax:].shape[0] - 1, cut_seg[:, :, m_ax:].shape[1] - 1, 0), 3) new_seg[np.where((cut_seg == 2) | (cut_seg == 3))] = 0 reg_seg = np.copy(new_seg) new_seg[:,:,m_ax:] = self.__choose_largest_co_component(np.copy(reg_seg[:, :, m_ax:]) , 1) new_seg = np.array(new_seg, dtype=np.int) new_seg[:,:,m_ax:] += self.__choose_largest_co_component(np.copy(reg_seg[:, :, m_ax:]) , 2) new_seg[:, :, :m_ax] = 0 min_sa, min_ca, min_a_a, max_s_a, max_c_a, max_a_a = self.__found_bounding_box(self.aorta_mat) new_seg[min_sa: max_s_a,min_ca:max_c_a,min_a_a: max_a_a] = 6 new_seg = np.array(new_seg, dtype=np.int) cut_seg = np.array(cut_seg, dtype=np.int) seg_file = nib.Nifti1Image(new_seg, self.ct_file.affine) seg_file1 = nib.Nifti1Image(cut_seg, self.ct_file.affine) seg_file2 = nib.Nifti1Image(new_seg1, self.ct_file.affine) nib.save(seg_file, self.dir_results + self.ct_scan + '_final_lungs_' + LUNG_SEG + NIFTY_END) nib.save(seg_file1, self.dir_results + self.ct_scan + '_air_and_lung_' + LUNG_SEG + NIFTY_END) nib.save(seg_file2, self.dir_results + self.ct_scan + '_raw_' + LUNG_SEG + NIFTY_END) return new_seg
def test_wraparound(): # If the borders (or neighbors) aren't correctly accounted for, this fails, # because the algorithm uses an ravelled array. test = np.zeros((5, 7), dtype=np.float64) test[:, 3] = 100 expected = np.array([[-1., -1., -1., 100., 0., 0., 0.], [-1., -1., -1., 100., 0., 0., 0.], [-1., -1., -1., 100., 0., 0., 0.], [-1., -1., -1., 100., 0., 0., 0.], [-1., -1., -1., 100., 0., 0., 0.]]) np.testing.assert_equal(flood_fill(test, (0, 0), -1), expected)
def test_basic_nd(): for dimension in (3, 4, 5): shape = (5,) * dimension hypercube = np.zeros(shape) slice_mid = tuple(slice(1, -1, None) for dim in range(dimension)) hypercube[slice_mid] = 1 # sum is 3**dimension filled = flood_fill(hypercube, (2,)*dimension, 2) # Test that the middle sum is correct assert filled.sum() == 3**dimension * 2 # Test that the entire array is as expected np.testing.assert_equal( filled, np.pad(np.ones((3,)*dimension) * 2, 1, 'constant'))
def test_basic_nd(): for dimension in (3, 4, 5): shape = (5, ) * dimension hypercube = np.zeros(shape) slice_mid = tuple(slice(1, -1, None) for dim in range(dimension)) hypercube[slice_mid] = 1 # sum is 3**dimension filled = flood_fill(hypercube, (2, ) * dimension, 2) # Test that the middle sum is correct assert filled.sum() == 3**dimension * 2 # Test that the entire array is as expected np.testing.assert_equal( filled, np.pad(np.ones((3, ) * dimension) * 2, 1, 'constant'))
def test_negative_indexing_seed_point(): image = np.array( [[0, 0, 0, 0, 0, 0, 0], [0, 1, 1, 0, 2, 2, 0], [0, 1, 1, 0, 2, 2, 0], [1, 0, 0, 0, 0, 0, 3], [0, 1, 1, 1, 3, 3, 4]], dtype=np.float32) expected = np.array( [[5., 5., 5., 5., 5., 5., 5.], [5., 1., 1., 5., 2., 2., 5.], [5., 1., 1., 5., 2., 2., 5.], [1., 5., 5., 5., 5., 5., 3.], [5., 1., 1., 1., 3., 3., 4.]], dtype=np.float32) image = flood_fill(image, (0, -1), 5) np.testing.assert_allclose(image, expected)
def flood_fill(self, event): """ Fills a contour selected by the middle mouse button with the mask. """ if event.widget is self.image_label: for i in range(3): self.mask[:, :, i] = flood_fill(self.mask[:, :, i], seed_point=(event.y, event.x), new_value=255, tolerance=1) self.display_image[:, :, i] = np.where(self.mask[:, :, i] == 255, 255, self.display_image[:, :, i]) self.update_image()
def office_has_path(office): desks = np.copy(office.desks) start_col = office.start_col start_row = desks.shape[0] - 1 # When you stand up, your desk becomes empty desks[start_row, start_col] = DESK_EMPTY # draw a path everywhere you can reach desks_with_path = flood_fill(desks, (start_row, start_col), DESK_PATH) # look for a path to any desk in the exit row path_found = any(DESK_PATH == desk for desk in desks_with_path[DESKROW_EXIT]) return path_found
def fill_holes(self, origin='center', **kwargs): """fill_holes https://docs.scipy.org/doc/scipy-0.15.1/reference/generated/scipy.ndimage.morphology.binary_fill_holes.html Args: structure (_np.array, optional): [description]. Defaults to _np.ones((3,3)). """ if isinstance(origin, str): if origin.lower() == 'center': h, w = self.shape origin = (h // 2, w // 2) image = skm.flood_fill(self, origin, 1, **kwargs) return image
def action_fill_hole(self, label, frame, x_location, y_location): ''' fill a "hole" in a cell annotation with the cell label. Doesn't check if annotation at (y,x) is zero (hole to fill) because that logic is handled in javascript. Just takes the click location, scales it to match the actual annotation size, then fills the hole with label (using skimage flood_fill). connectivity = 1 prevents hole fill from spilling out into background in some cases ''' # rescale click location -> corresponding location in annotation array hole_fill_seed = (y_location // self.scale_factor, x_location // self.scale_factor) # fill hole with label img_ann = self.tracked[frame,:,:,0] filled_img_ann = flood_fill(img_ann, hole_fill_seed, label, connectivity = 1) self.tracked[frame,:,:,0] = filled_img_ann self.frames_changed = True
def action_flood_contiguous(self, label, frame, x_location, y_location): ''' flood fill a cell with a unique new label; alternative to watershed for fixing duplicate label issue if cells are not touching ''' img_ann = self.tracked[frame,:,:,0] old_label = label new_label = max(self.tracks) + 1 in_original = np.any(np.isin(img_ann, old_label)) filled_img_ann = flood_fill(img_ann, (int(y_location/self.scale_factor), int(x_location/self.scale_factor)), new_label) self.tracked[frame,:,:,0] = filled_img_ann in_modified = np.any(np.isin(filled_img_ann, old_label)) # update cell info dicts since labels are changing self.add_cell_info(add_label=new_label, frame = frame) if in_original and not in_modified: self.del_cell_info(del_label = old_label, frame = frame)
def test_float16(): image = np.array([9., 0.1, 42], dtype=np.float16) with raises(TypeError, match="dtype of `image` is float16"): flood_fill(image, 0, 1)