def test_li_camera_image(): image = skimage.img_as_ubyte(data.camera()) threshold = threshold_li(image) ce_actual = _cross_entropy(image, threshold) assert 62 < threshold_li(image) < 63 assert ce_actual < _cross_entropy(image, threshold + 1) assert ce_actual < _cross_entropy(image, threshold - 1)
def test_li_arbitrary_start_point(): cell = data.cell() max_stationary_point = threshold_li(cell) low_stationary_point = threshold_li(cell, initial_guess=np.percentile(cell, 5)) optimum = threshold_li(cell, initial_guess=np.percentile(cell, 95)) assert 67 < max_stationary_point < 68 assert 48 < low_stationary_point < 49 assert 111 < optimum < 112
def test_li_coins_image(): image = skimage.img_as_ubyte(data.coins()) threshold = threshold_li(image) ce_actual = _cross_entropy(image, threshold) assert 94 < threshold_li(image) < 95 assert ce_actual < _cross_entropy(image, threshold + 1) # in the case of the coins image, the minimum cross-entropy is achieved one # threshold below that found by the iterative method. Not sure why that is # but `threshold_li` does find the stationary point of the function (ie the # tolerance can be reduced arbitrarily but the exact same threshold is # found), so my guess some kind of histogram binning effect. assert ce_actual < _cross_entropy(image, threshold - 2)
def test_li_astro_image(): image = skimage.img_as_ubyte(data.astronaut()) threshold = threshold_li(image) ce_actual = _cross_entropy(image, threshold) assert 64 < threshold < 65 assert ce_actual < _cross_entropy(image, threshold + 1) assert ce_actual < _cross_entropy(image, threshold - 1)
def test_li_pathological_arrays(): # See https://github.com/scikit-image/scikit-image/issues/4140 a = np.array([0, 0, 1, 0, 0, 1, 0, 1]) b = np.array([0, 0, 0.1, 0, 0, 0.1, 0, 0.1]) c = np.array([0, 0, 0.1, 0, 0, 0.1, 0.01, 0.1]) d = np.array([0, 0, 1, 0, 0, 1, 0.5, 1]) e = np.array([1, 1]) f = np.array([1, 2]) arrays = [a, b, c, d, e, f] thresholds = [threshold_li(arr) for arr in arrays] assert np.all(np.isfinite(thresholds))
def test_li_pathological_arrays(): # See https://github.com/scikit-image/scikit-image/issues/4140 a = np.array([0, 0, 1, 0, 0, 1, 0, 1]) b = np.array([0, 0, 0.1, 0, 0, 0.1, 0, 0.1]) c = np.array([0, 0, 0.1, 0, 0, 0.1, 0.01, 0.1]) d = np.array([0, 0, 1, 0, 0, 1, 0.5, 1]) e = np.array([1, 1]) f = np.array([1, 2]) arrays = [a, b, c, d, e, f] with np.errstate(divide='ignore'): # ignoring "divide by zero encountered in log" error from np.log(0) thresholds = [threshold_li(arr) for arr in arrays] assert np.all(np.isfinite(thresholds))
def test_li_negative_int(self): image = self.image - 2 assert int(threshold_li(image)) == 0
def segment_nuclei_3Dstack_victoria(stack, min_nuc_center_dist=25, sigma=5, usemax=False, display=False, return_intermediates=False, seed_window=None): """Segment nuclei from Rpb1 fluorescence in confocal data. Algorithm is smooth -> threshold -> gradient -> distance transform to find seeds -> take gradient on binary mask -> watershed on gradient. Does not do any filtering on resulting segmented objects. Args: stack: ndarray 3D image stack of dimensions [z, x, y]. seed_window: tuple of three ints Size in [z, x, y] for window for determining local maxes in distance transform. A point is retained as a seed if there exists some window of this size in the image for which the point is the max value. Generally want size to be a little less than 2x the distance between nuclear centers. Centers closer than this will not produce two seeds. min_nuc_center_dist: numeric The minimum euclidean distance (in pixels) allowed between watershed seeds. Typically set as ~the diameter of the nuclei. sigma: numeric Sigma for use in initial gaussian smoothing usemax: bool Use maximum intensity projection (in Z) for segmenting return_intermediates: bool Return (mask, grad, seeds, ws) for troubleshooting seed_window: tuple of ints [Optional] Size in [z, x, y] for window for determining local maxes in distance transform. A point is retained as a seed if there exists some window of this size in the image for which the point is the max value. Generally want size to be a little less than 2x the distance between nuclear centers. Centers closer than this will not produce two seeds. If None, then a seed window is automatically generated from min_nuc_center_dist so that the diagonal of the box is equal to twice this distance. Returns: labelmask: ndarray Mask of same shape as input stack with nuclei segmented and labeled """ # Generate seed window if none supplied. if seed_window is None: # Window set such that the diagonal is equal to 2 * min_nuc_center_dist. seed_window = (stack.shape[0], (min_nuc_center_dist * 2) / np.sqrt(2), (min_nuc_center_dist * 2) / np.sqrt(2)) # Remove first dimension if max projection used. if usemax: seed_window = seed_window[1:] # Smooth stack using a Gaussian filter. if usemax: stack_medfilt = ndi.median_filter(stack.max(axis=0), 15) stack_smooth = ndi.gaussian_filter(stack_medfilt, sigma) else: stack_smooth = ndi.gaussian_filter(stack, sigma) # Define a threshold for nuclear signal. thresh = threshold_li(stack_smooth) print(thresh) # Make a binary mask using threshold. mask = np.where(stack_smooth > thresh, 1, 0) # Take the gradient of the mask to produce outlines for use in watershed algorithm. grad = gradient_nD(mask) # Perform distance transform and run local max finder to determine watershed seeds. dist = ndi.distance_transform_edt(mask) seeds, _ = peak_local_max_nD(dist, size=seed_window, min_dist=min_nuc_center_dist) # Perform watershed segmentation. ws = watershed(grad, seeds.astype(int)) # Filter object size and circularity, relabel to set background to 0. if usemax: ws = np.repeat(np.expand_dims(ws, axis=0), stack.shape[0], axis=0) labelmask = ws if (display): if usemax: mask = np.expand_dims(mask, 0) seeds = np.expand_dims(seeds, 0) stack_smooth = np.expand_dims(stack_smooth, 0) grad = np.expand_dims(grad, 0) fig, ax = plt.subplots(3, 2, figsize=(10, 10)) # Display mask. ax[0][0].imshow(mask.max(axis=0)) ax[0][0].set_title('Initial Mask') # Display watershed seeds. seeds_vis = ndi.morphology.binary_dilation(seeds.max(axis=0), structure=np.ones((8, 8))) ax[0][1].imshow(stack_smooth.max(axis=0), alpha=0.5) ax[0][1].imshow(seeds_vis, alpha=0.5) ax[0][1].set_title('Watershed seeds') # Display gradient. ax[1][0].imshow(grad.max(axis=0)) ax[1][0].set_title('Gradient') # Display watershed output. ws = relabel_labelmask(ws) ax[1][1].imshow(ws.astype('bool').max(axis=0)) ax[1][1].set_title('Watershed') # Display final mask. ax[2][0].imshow(labelmask.astype('bool').max(axis=0)) ax[2][0].set_title('Final Segmentation') if return_intermediates: return (mask, grad, seeds, ws) return labelmask
def test_li_coins_image(): coins = skimage.img_as_ubyte(data.coins()) assert 95 < threshold_li(coins) < 97
def test_li_astro_image(): img = skimage.img_as_ubyte(data.astronaut()) assert 66 < threshold_li(img) < 68
def test_li_coins_image_as_float(): coins = skimage.img_as_float(data.coins()) assert 0.37 < threshold_li(coins) < 0.38
def test_li_constant_image(self): with pytest.raises(ValueError): threshold_li(np.ones((10,10)))
def time_float32_image(self): result1 = threshold_li(self.image_float32)
def test_li_float_image(self): image = np.float64(self.image) assert 2 <= threshold_li(image) < 3
def test_li_coins_image_as_float(): coins = skimage.img_as_float(data.coins()) assert 94/255 < threshold_li(coins) < 95/255
def test_li_nan_image(): image = np.full((5, 5), np.nan) assert np.isnan(threshold_li(image))
def test_li_constant_image(self): with testing.raises(ValueError): threshold_li(np.ones((10, 10)))
def test_li_camera_image(): camera = skimage.img_as_ubyte(data.camera()) assert 63 < threshold_li(camera) < 65
def test_li_negative_inital_guess(): coins = data.coins() with testing.raises(ValueError): result = threshold_li(coins, initial_guess=-5)
def test_li_coins_image_as_float(): coins = skimage.img_as_float(data.coins()) assert 94 / 255 < threshold_li(coins) < 95 / 255
def test_li_inf_minus_inf(): image = np.array([np.inf, -np.inf]) assert threshold_li(image) == 0
def test_li(self): assert int(threshold_li(self.image)) == 2
def time_integer_image(self): result1 = threshold_li(self.image)
def test_li(self): assert 2 < threshold_li(self.image) < 3
def test_li_float_image(self): image = self.image.astype(float) assert 2 < threshold_li(image) < 3
def test_li_inf_image(): image = np.array([np.inf, np.nan]) assert threshold_li(image) == np.inf
def test_li_constant_image_with_nan(): image = np.array([8, 8, 8, 8, np.nan]) assert threshold_li(image) == 8
def test_li_negative_int(self): image = self.image - 2 assert 0 < threshold_li(image) < 1
def test_li_constant_image(self): assert threshold_li(np.ones((10, 10))) == 1.
def test_li_negative_inital_guess(): coins = data.coins() with pytest.raises(ValueError): threshold_li(coins, initial_guess=-5)