def segment_volume_mc(pmaps, threshold=0.4, sigma=2.0, beta=0.6, ws=None, sp_min_size=100): if ws is None: ws = distance_transform_watershed(pmaps, threshold, sigma, min_size=sp_min_size)[0] rag = compute_rag(ws, 1) features = nrag.accumulateEdgeMeanAndLength(rag, pmaps, numberOfThreads=1) probs = features[:, 0] # mean edge prob edge_sizes = features[:, 1] costs = transform_probabilities_to_costs(probs, edge_sizes=edge_sizes, beta=beta) graph = nifty.graph.undirectedGraph(rag.numberOfNodes) graph.insertEdges(rag.uvIds()) node_labels = multicut_kernighan_lin(graph, costs) return nifty.tools.take(node_labels, ws)
def segment_volume(self, pmaps): if self.ws_2D: # WS in 2D ws = self.ws_dt_2D(pmaps) else: # WS in 3D ws, _ = distance_transform_watershed(pmaps, self.ws_threshold, self.ws_sigma, sigma_weights=self.ws_w_sigma, min_size=self.ws_minsize) rag = compute_rag(ws, 1) # Computing edge features features = nrag.accumulateEdgeMeanAndLength( rag, pmaps, numberOfThreads=1) # DO NOT CHANGE numberOfThreads probs = features[:, 0] # mean edge prob edge_sizes = features[:, 1] # Prob -> edge costs costs = transform_probabilities_to_costs(probs, edge_sizes=edge_sizes, beta=self.beta) # Creating graph graph = nifty.graph.undirectedGraph(rag.numberOfNodes) graph.insertEdges(rag.uvIds()) # Solving Multicut node_labels = multicut_kernighan_lin(graph, costs) return nifty.tools.take(node_labels, ws)
def test_distance_transform_watershed_2d(self): from elf.segmentation.watershed import distance_transform_watershed shape = (256, 256) inp = np.random.rand(*shape).astype('float32') # test for different options configs = [{ 'sigma_seeds': 2. }, { 'sigma_seeds': 2., 'pixel_pitch': (1, 1) }, { 'sigma_seeds': 2., 'pixel_pitch': (4, 2) }, { 'sigma_seeds': 0., 'sigma_weights': 0., 'min_size': 0 }] for config in configs: ws, max_id = distance_transform_watershed(inp, threshold=.5, **config) self.assertEqual(inp.shape, ws.shape) # make sure result is non-trivial self.assertGreater(max_id, 32) self.assertEqual(ws.max(), max_id) self.assertNotIn(0, ws)
def execute(self, slot, subindex, roi, result): assert slot is self.Superpixels, "Unknown or unconnected output slot: {}".format( slot) pmap = self._opSelectedInput.Output(roi.start, roi.stop).wait() if self.debug_results: self.debug_results.clear() # distance_transform_watershed expects a default value of None for pixel_pitch. if self.PixelPitch.value == []: pixel_pitch_to_pass = None else: pixel_pitch_to_pass = self.PixelPitch.value ws, max_id = distance_transform_watershed( pmap[..., 0], self.Threshold.value, self.Sigma.value, self.Sigma.value, self.MinSize.value, self.Alpha.value, pixel_pitch_to_pass, self.ApplyNonmaxSuppression.value, ) result[..., 0] = ws self.watershed_completed()
def test_distance_transform_watershed_suppression(self): from elf.segmentation.watershed import distance_transform_watershed shape = (256, 256) inp = np.random.rand(*shape).astype('float32') ws, max_id = distance_transform_watershed( inp, threshold=.5, sigma_seeds=2., apply_nonmax_suppression=True) self.assertEqual(inp.shape, ws.shape) # make sure result is non-trivial self.assertGreater(max_id, 32) self.assertEqual(ws.max(), max_id) self.assertNotIn(0, ws)
def ws_dt_2D(self, pmaps): # Axis 0 is assumed z-axis!!! ws = np.zeros_like(pmaps).astype(np.uint32) max_idx = 1 for i in range(pmaps.shape[0]): _pmaps = pmaps[i] _ws, _ = distance_transform_watershed(_pmaps, self.ws_threshold, self.ws_sigma, sigma_weights=self.ws_w_sigma, min_size=self.ws_minsize) _ws = _ws + max_idx max_idx = _ws.max() ws[i] = _ws return ws
def segment_volume_lmc_from_seg(boundary_pmaps, nuclei_seg, threshold=0.4, sigma=2.0, sp_min_size=100): watershed = distance_transform_watershed(boundary_pmaps, threshold, sigma, min_size=sp_min_size)[0] # compute the region adjacency graph rag = compute_rag(watershed) # compute the edge costs features = compute_boundary_mean_and_length(rag, boundary_pmaps) costs, sizes = features[:, 0], features[:, 1] # transform the edge costs from [0, 1] to [-inf, inf], which is # necessary for the multicut. This is done by intepreting the values # as probabilities for an edge being 'true' and then taking the negative log-likelihood. # in addition, we weight the costs by the size of the corresponding edge # we choose a boundary bias smaller than 0.5 in order to # decrease the degree of over segmentation boundary_bias = .6 costs = transform_probabilities_to_costs(costs, edge_sizes=sizes, beta=boundary_bias) max_cost = np.abs(np.max(costs)) lifted_uvs, lifted_costs = lifted_problem_from_segmentation( rag, watershed, nuclei_seg, overlap_threshold=0.2, graph_depth=4, same_segment_cost=5 * max_cost, different_segment_cost=-5 * max_cost) # solve the full lifted problem using the kernighan lin approximation introduced in # http://openaccess.thecvf.com/content_iccv_2015/html/Keuper_Efficient_Decomposition_of_ICCV_2015_paper.html node_labels = lmc.lifted_multicut_kernighan_lin(rag, costs, lifted_uvs, lifted_costs) lifted_segmentation = project_node_labels_to_pixels(rag, node_labels) return lifted_segmentation
def get_result_function(input_data): """ Returns the result of the watershed algorithm directly from the core function. """ ws, max_id = distance_transform_watershed( input_data[..., 0], WS_PARAMS["threshold"], WS_PARAMS["sigma"], WS_PARAMS["sigma"], WS_PARAMS["min_size"], WS_PARAMS["alpha"], WS_PARAMS["pixel_pitch"], WS_PARAMS["apply_nonmax_suppression"], ) return ws, max_id
def test_distance_transform_watershed_masked(self): from elf.segmentation.watershed import distance_transform_watershed shape = (32, 128, 128) inp = np.random.rand(*shape).astype('float32') mask = np.zeros(shape, dtype='bool') mask[8:24, 28:100, 37:93] = 1 # test for different options ws, max_id = distance_transform_watershed(inp, threshold=.5, mask=mask, sigma_seeds=2.) self.assertEqual(inp.shape, ws.shape) # make sure result is non-trivial self.assertGreater(max_id, 32) self.assertEqual(ws.max(), max_id) self.assertNotIn(0, ws[mask]) self.assertTrue((ws[np.logical_not(mask)] == 0).all())