def execute(self, slot, subindex, roi, result): assert slot is self.Superpixels, "Unknown or unconnected output slot: {}".format( slot) channel_index = self.ChannelSelection.value pmap_roi = roi.copy() pmap_roi.start[-1] = channel_index pmap_roi.stop[-1] = channel_index + 1 # TODO: We could be sneaky and use the result array as a temporary here... pmap = self.Input(pmap_roi.start, pmap_roi.stop).wait() if self.debug_results: self.debug_results.clear() wsDtSegmentation(pmap[..., 0], self.Pmin.value, self.MinMembraneSize.value, self.MinSegmentSize.value, self.SigmaMinima.value, self.SigmaWeights.value, self.GroupSeeds.value, self.PreserveMembranePmaps.value, out_debug_image_dict=self.debug_results, out=result[..., 0]) self.watershed_completed()
def test_out_param(self): pmap = self._gen_input_data(2) debug_results = {} preallocated = np.random.randint(0, 100, pmap.shape).astype(np.uint32) ws_output = wsDtSegmentation(pmap, 0.5, 0, 10, 0.1, 0.1, groupSeeds=False, out_debug_image_dict=debug_results, out=preallocated) assert ws_output is preallocated seeds = debug_results['seeds'][:] assert seeds.max() == 4 assert ws_output.max() == 4 # Also with groupSeeds=True preallocated = np.random.randint(0, 100, pmap.shape).astype(np.uint32) ws_output = wsDtSegmentation(pmap, 0.5, 0, 10, 0.1, 0.1, groupSeeds=True, out_debug_image_dict=debug_results, out=preallocated) assert ws_output is preallocated assert seeds.max() == 4 assert ws_output.max() == 4
def execute(self, slot, subindex, roi, result): assert slot is self.Superpixels, "Unknown or unconnected output slot: {}".format( slot ) channel_index = self.ChannelSelection.value pmap_roi = roi.copy() pmap_roi.start[-1] = channel_index pmap_roi.stop[-1] = channel_index+1 # TODO: We could be sneaky and use the result array as a temporary here... pmap = self.Input(pmap_roi.start, pmap_roi.stop).wait() if self.debug_results: self.debug_results.clear() wsDtSegmentation( pmap[...,0], self.Pmin.value, self.MinMembraneSize.value, self.MinSegmentSize.value, self.SigmaMinima.value, self.SigmaWeights.value, self.GroupSeeds.value, self.PreserveMembranePmaps.value, out_debug_image_dict=self.debug_results, out=result[...,0] ) self.watershed_completed()
def test_simple_2D(self): pmap = self._gen_input_data(2) debug_results = {} ws_output = wsDtSegmentation(pmap, 0.5, 0, 10, 0.1, 0.1, groupSeeds=False, out_debug_image_dict=debug_results) seeds = debug_results['seeds'][:] assert seeds.max() == 4 assert ws_output.max() == 4 # Expect seeds at (25,25,25), (25,25,75), (25,75,25), etc... expected_seed_coords = list(np.ndindex((2, 2))) expected_seed_coords = 50 * np.array(expected_seed_coords) + 25 #print "EXPECTED:\n", expected_seed_coords #print "SEEDS:\n", np.array(np.where(seeds)).transpose() for seed_coord in expected_seed_coords: assert seeds[tuple(seed_coord)], "No seed at: {}".format( seed_coord)
def ws_distance_transform(pmap, threshold, sigma_seeds, sigma_weights=0., min_membrane_size=0, min_segment_size=0, group_seeds=False, preserve_membrane=True, grow_on_pmap=True, out_debug_dict=None): """ Watershed on distance transform on 2d or 3d probabiity map. @params: pmap: probability map, 2d or 3d numpy.ndarray of type float32. threshold: threshold for pixels that are considered in distance transform. sigma_seeds: smoothing factor for distance transform used for finding seeds. sigma_weights: smoothing factor for heiht map used for the watershed (default 0.). min_membrane_size: size filter for connected membrane components after thresholding (default 0 -> no size filtering). min_segment_size: size filter for resulting segments (default 0 -> no size filtering). group_seeds: use heuristics to group adjacent seeds (default: False). preserve_membrane: preserve membrane seeds (default: False). grow_on_pmap: grow on the probability map instead of distance transform (default: True). out_debug_dict: dictionary to store debug images as chunked arrays (default: None). @returns: fragments: numpy.ndarray of type uint32 n_labels: number of labels """ fragments, max_label = wsDtSegmentation(pmap, threshold, min_membrane_size, min_segment_size, sigma_seeds, sigma_weights, group_seeds, preserve_membrane, grow_on_pmap, out_debug_dict) return fragments - 1, max_label
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() wsDtSegmentation( pmap[...,0], self.Pmin.value, self.MinMembraneSize.value, self.MinSegmentSize.value, self.SigmaMinima.value, self.SigmaWeights.value, self.GroupSeeds.value, self.PreserveMembranePmaps.value, out_debug_image_dict=self.debug_results, out=result[...,0] ) self.watershed_completed()
def test_group_seeds_ram_usage(self): """ The original implementation of the groupSeeds option needed a lot of RAM, scaling with the number of seeds by N**2. The new implementation does the work in batches, so it doesn't need as much RAM. Here we create a test image that will result in lots of seeds, and we'll verify that RAM usage stays under control. The test image looks roughly like this (seeds marked with 'x'): +-----------------------------------------------------+ | | | | | | | | | | | | | | | | | | | | | | | | x x x x x x x x x x x x x x | | | | | +-----------------------------------------------------+ """ input_data = np.zeros((101, 20001), dtype=np.float32) # Add borders input_data[0] = 1 input_data[-1] = 1 input_data[:, 0] = 1 input_data[:, -1] = 1 # Add tick marks input_data[:10, ::10] = 1 # Sanity check, try without groupSeeds, make sure we've got a lot of segments ws_output = wsDtSegmentation(input_data, 0.5, 0, 0, 0.0, 0.0, groupSeeds=False) assert ws_output.max() > 1900 # Now check RAM with groupSeeds=True ws_output = assert_mem_usage_factor(3.0)(wsDtSegmentation)( input_data, 0.5, 0, 0, 2.0, 0.0, groupSeeds=True) assert ws_output.max() == 1
def create_supervoxels_with_wsdt( boundary_volume, mask, boundary_channel=0, pmin=0.5, minMembraneSize=10000, minSegmentSize=300, sigmaMinima=3, sigmaWeights=1.6, groupSeeds=False, preserve_membrane_pmaps=False ): """ Generate supervoxels using Timo's watershed of the distance-transform method. """ logger = logging.getLogger(__name__) logger.info('status=wsdt supervoxels') assert boundary_volume.ndim == 4, "Expected a 4D volume." boundary_volume = boundary_volume[..., boundary_channel] if mask is not None: # Forbid the watershed from bleeding into the masked area prematurely mask = mask.astype(np.bool, copy=False) # Mask is now inverted inverted_mask = np.logical_not(mask, out=mask) boundary_volume[inverted_mask] = 2.0 watershed = wsdt.wsDtSegmentation( boundary_volume, pmin, minMembraneSize, minSegmentSize, sigmaMinima, sigmaWeights, groupSeeds, preserve_membrane_pmaps) if mask is not None: watershed[inverted_mask] = 0 #logger.warn("FIXME: Saving watershed to temporary file for debugging purposes...") #tmpdir = tempfile.mkdtemp(prefix="wsdt_output_") #watershed_path = os.path.join(tmpdir, 'watershed.h5') #with h5py.File(watershed_path, 'w') as watershed_file: # watershed_file.create_dataset('watershed', data=watershed) logger.info('status=wsdt supervoxels finished') return watershed
def wsdt(prob_map): # off the shelve settings threshold = 0.3 minMemSize = 50 minSegSize = 75 sigMinima = 2.0 sigWeights = 2.6 groupSeeds = False segmentation, _ = wsDtSegmentation(prob_map, threshold, minMemSize, minSegSize, sigMinima, sigWeights, groupSeeds) if not 0 in segmentation: segmentation -= 1 return segmentation
def superpixels(pmaps, outfile=None): import wsdt from wsdt import wsDtSegmentation # 2d distance transform superpixel for the probability maps #pmap_path = "/path/to/neurocut_examples/probability_map.h5" #pmap_key = "data" #pmaps = vigra.readHDF5(pmap_path, pmap_key) # parameters for the watershed on distance trafo # threshold for computing the distance trafo threshold = 0.5 # minimal size of connected components that are taken into account # for the distance trafo min_mem = 50 # minimal size of segments in the result min_seg = 75 # sigma for smoothing the seed map sig_seeds = 1.6 # sigma for smoothing the weight map sig_weights = 2.0 segmentation = numpy.zeros_like(pmaps, dtype = numpy.uint32) # we need an offset for each slice, because we need distinct ids in each slice offset = 0 # iterate over the z-slices and perform the wsdt in each #for z in xrange(segmentation.shape[2]): segmentation[:,:] = wsDtSegmentation( pmaps[:,:], threshold, min_mem, min_seg, sig_seeds, sig_weights) # add the offset #segmentation[:,:] += offset # get the new offset #offset = numpy.max(segmentation) # save the result if outfile is not None: save_key = "superpixel" vigra.writeHDF5(segmentation, outfile, save_key) return segmentation
def create_supervoxels_with_wsdt( boundary_volume, mask, boundary_channel=0, pmin=0.5, minMembraneSize=10000, minSegmentSize=300, sigmaMinima=3, sigmaWeights=1.6, cleanCloseSeeds=False ): """ Generate supervoxels using Timo's watershed of the distance-transform method. """ assert boundary_volume.ndim == 4, "Expected a 4D volume." boundary_volume = boundary_volume[..., boundary_channel] if mask is not None: # Forbid the watershed from bleeding into the masked area prematurely mask = mask.astype(np.bool, copy=False) # Mask is now inverted inverted_mask = np.logical_not(mask, out=mask) boundary_volume[inverted_mask] = 2.0 watershed = wsdt.wsDtSegmentation( boundary_volume, pmin, minMembraneSize, minSegmentSize, sigmaMinima, sigmaWeights, cleanCloseSeeds=False, returnSeedsOnly=False ) if mask is not None: watershed[inverted_mask] = 0 #logger.warn("FIXME: Saving watershed to temporary file for debugging purposes...") #tmpdir = tempfile.mkdtemp(prefix="wsdt_output_") #watershed_path = os.path.join(tmpdir, 'watershed.h5') #with h5py.File(watershed_path, 'w') as watershed_file: # watershed_file.create_dataset('watershed', data=watershed) return watershed
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() ws, max_label = wsDtSegmentation( pmap[..., 0], self.Pmin.value, self.MinMembraneSize.value, self.MinSegmentSize.value, self.SigmaMinima.value, self.SigmaWeights.value, self.GroupSeeds.value, self.PreserveMembranePmaps.value, out_debug_image_dict=self.debug_results, out=result[..., 0]) self.watershed_completed()
def watersheds(prob_map): threshold = 0.25 # off the shelve settings minMemSize = 15 minSegSize = 30 sigMinima = 2.0 sigWeights = 2.6 groupSeeds = True segmentation = np.zeros_like(prob_map, dtype = np.uint32) offset = 0 for z in xrange(prob_map.shape[2]): wsdt, _ = wsDtSegmentation(prob_map[:,:,z], threshold, minMemSize, minSegSize, sigMinima, sigWeights, groupSeeds) segmentation[:,:,z] = wsdt segmentation[:,:,z] += offset offset = np.max(segmentation) return segmentation
def test_debug_output(self): """ Just exercise the API for debug images, even though we're not really checking the *contents* of the images in this test. """ pmap = self._gen_input_data(3) debug_images = {} ws_output = wsDtSegmentation(pmap, 0.5, 0, 10, 0.1, 0.1, groupSeeds=False, out_debug_image_dict=debug_images) assert ws_output.max() == 8 assert 'thresholded membranes' in debug_images assert debug_images['thresholded membranes'].shape == ws_output.shape assert 'filtered membranes' in debug_images assert debug_images['filtered membranes'].shape == ws_output.shape
def test_border_seeds(self): """ check if seeds at the borders are generated """ # create a volume with membrane evidence everywhere pmap = np.ones((50, 50, 50)) # create funnel without membrane evidence growing larger towards the block border. pmap[0, 12:39, 12:39] = 0 pmap[1:50, 13:38, 13:38] = 0 debug_results = {} _ws_output = wsDtSegmentation(pmap, 0.5, 0, 10, 0.1, 0.1, groupSeeds=False, out_debug_image_dict=debug_results) seeds = debug_results['seeds'][:] assert seeds.sum() == 1 assert seeds[0, 25, 25] == 1
def wsdt(prob_map): threshold = 0.3 minMemSize = 1 minSegSize = 1 sigMinima = 2.0 sigWeights = 2.6 groupSeeds = False segmentation = np.zeros_like(prob_map, dtype=np.uint32) offset = 0 for z in xrange(prob_map.shape[2]): wsdt, _ = wsDtSegmentation(prob_map[:, :, z], threshold, minMemSize, minSegSize, sigMinima, sigWeights, groupSeeds) if not 0 in wsdt: wsdt -= 1 segmentation[:, :, z] = wsdt segmentation[:, :, z] += offset offset = np.max(segmentation) + 1 return segmentation
def make_ws(inp, thresh, sig_min): return wsDtSegmentation(inp, thresh, 25, 50, sig_min, 0., True)
def test_group_close_seeds(self): """ In this test we'll use input data that looks roughly like the following: 0 101 202 303 0 +-----------------+-----------------+-----------------+ | | | | | | | | | | | | | | | | | 50 | x x y y | z | | | | | | | | | | | | | | | | | | 101 +-----------------+-----------------+-----------------+ The x and y markers indicate where seeds will end up. With groupSeeds=False, we get 5 seed points and 5 final segments. But with groupSeeds=True, the two x points end up in the same segment, and the two y points end up in the same segment. The lone z point will not be merged with anything. """ input_data = np.zeros((101, 303), dtype=np.float32) # Add borders input_data[0] = 1 input_data[-1] = 1 input_data[:, 0] = 1 input_data[:, -1] = 1 # Add complete divider for the z compartment input_data[:, 202] = 1 # Add notches extending from the upper/lower borders input_data[1:10, 51] = 1 input_data[1:40, 101] = 1 input_data[1:10, 151] = 1 input_data[-10:-1, 51] = 1 input_data[-40:-1, 101] = 1 input_data[-10:-1, 151] = 1 # First, try without groupSeeds debug_results = {} ws_output = wsDtSegmentation(input_data, 0.5, 0, 0, 0.0, 0.0, groupSeeds=False, out_debug_image_dict=debug_results) assert ws_output.max() == 5 # Now, with groupSeeds=True, the left-hand seeds should # be merged and the right-hand seeds should be merged debug_results = {} ws_output = wsDtSegmentation(input_data, 0.5, 0, 0, 0.0, 0.0, groupSeeds=True, out_debug_image_dict=debug_results) assert ws_output.max() == 3 assert (ws_output[:, 0:90] == ws_output[51, 51]).all() assert (ws_output[:, 110:190] == ws_output[51, 151]).all() assert (ws_output[:, 210:290] == ws_output[51, 251]).all() # The segment values are different assert ws_output[51, 51] != ws_output[51, 151] != ws_output[51, 251]