def _make_seeds(dt, config): sigma_seeds = config.get('sigma_seeds', 2.) apply_nonmax_suppression = config.get('non_maximum_suppression', True) if apply_nonmax_suppression and nonMaximumDistanceSuppression is None: fu.log("non-maximum suppression was activated, but is not available") apply_nonmax_suppression = False # find local maxima of the distance transform max_fu = vigra.analysis.localMaxima if dt.ndim == 2 else vigra.analysis.localMaxima3D if sigma_seeds: seeds = max_fu(vu.apply_filter(dt, 'gaussianSmoothing', sigma_seeds), marker=np.nan, allowAtBorder=True, allowPlateaus=True) else: seeds = max_fu(dt, marker=np.nan, allowAtBorder=True, allowPlateaus=True) # check if we have just one plateau seeds = np.isnan(seeds) if np.sum(seeds) == seeds.size: return np.ones_like(seeds, dtype='uint32') # find seeds via connected components after max-suppression if enabled) if apply_nonmax_suppression: seeds = np.array(np.where(seeds)).transpose() seeds = nonMaximumDistanceSuppression(dt, seeds) seeds = _points_to_vol(seeds, dt.shape) else: seeds = vigra.analysis.labelMultiArrayWithBackground( seeds.view('uint8')) return seeds
def _threshold_block(block_id, blocking, ds_in, ds_out, threshold, threshold_mode, channel, sigma): fu.log("start processing block %i" % block_id) block = blocking.getBlock(block_id) bb = vu.block_to_bb(block) bb = vu.block_to_bb(block) if channel is None: input_ = ds_in[bb] else: channel_ = [channel] if isinstance(channel, int) else channel in_shape = (len(channel_), ) + tuple(b.stop - b.start for b in bb) input_ = np.zeros(in_shape, dtype=ds_in.dtype) for chan_id, chan in enumerate(channel_): bb_inp = (slice(chan, chan + 1), ) + bb input_[chan_id] = ds_in[bb_inp].squeeze() input_ = np.mean(input_, axis=0) input_ = vu.normalize(input_) if sigma > 0: input_ = vu.apply_filter(input_, 'gaussianSmoothing', sigma) input_ = vu.normalize(input_) if threshold_mode == 'greater': input_ = input_ > threshold elif threshold_mode == 'less': input_ = input_ < threshold elif threshold_mode == 'equal': input_ = input_ == threshold else: raise RuntimeError("Thresholding Mode %s not supported" % threshold_mode) ds_out[bb] = input_.astype('uint8') fu.log_block_success(block_id)
def _make_hmap(input_, distances, alpha, sigma_weights): distances = 1. - vu.normalize(distances) hmap = alpha * input_ + (1. - alpha) * distances # smooth input if sigma is given if sigma_weights != 0: hmap = vu.apply_filter(hmap, 'gaussianSmoothing', sigma_weights) return hmap
def _apply_watershed(input_, dt, offset, config, mask=None): apply_2d = config.get('apply_ws_2d', True) sigma_seeds = config.get('sigma_seeds', 2.) sigma_weights = config.get('sigma_weights', 2.) size_filter = config.get('size_filter', 25) alpha = config.get('alpha', 0.2) # apply the watersheds in 2d if apply_2d: ws = np.zeros_like(input_, dtype='uint64') for z in range(ws.shape[0]): # compute seeds for this slice dtz = vu.apply_filter(dt[z], 'gaussianSmoothing', sigma_seeds) if sigma_seeds != 0 else dt[z] seeds = vigra.analysis.localMaxima(dtz, marker=np.nan, allowAtBorder=True, allowPlateaus=True) seeds = vigra.analysis.labelImageWithBackground(np.isnan(seeds).view('uint8')) # run watershed for this slice hmap = _make_hmap(input_[z], dtz, alpha, sigma_weights) wsz, max_id = vu.watershed(hmap, seeds=seeds, size_filter=size_filter) # mask seeds if we have a mask if mask is None: wsz += offset else: wsz[mask[z]] = 0 inv_mask = np.logical_not(mask[z]) # NOTE we might have no pixels in the mask for this slice max_id = int(wsz[inv_mask].max()) if inv_mask.sum() > 0 else 0 wsz[inv_mask] += offset ws[z] = wsz offset += max_id # apply the watersheds in 3d else: if sigma_seeds != 0: dt = vu.apply_filter(dt, 'gaussianSmoothing', sigma_seeds) seeds = vigra.analysis.localMaxima3D(dt, marker=np.nan, allowAtBorder=True, allowPlateaus=True) seeds = vigra.analysis.labelVolumeWithBackground(np.isnan(seeds).view('uint8')) hmap = _make_hmap(input_, dt, alpha, sigma_weights) ws, max_id = vu.watershed(hmap, seeds, size_filter=size_filter) ws += offset # check if we have a mask if mask is not None: ws[mask] = 0 return ws
def _apply_filter(blocking, block_id, ds_in, ds_out, halo, filter_name, sigma, apply_in_2d): fu.log("start processing block %i" % block_id) block = blocking.getBlockWithHalo(block_id, halo) bb_in = vu.block_to_bb(block.outerBlock) input_ = vu.normalize(ds_in[bb_in]) response = vu.apply_filter(input_, filter_name, sigma, apply_in_2d) bb_out = vu.block_to_bb(block.innerBlock) inner_bb = vu.block_to_bb(block.innerBlockLocal) ds_out[bb_out] = response[inner_bb] fu.log_block_success(block_id)
def _cc_block_with_mask(block_id, blocking, ds_in, ds_out, threshold, threshold_mode, mask, channel, sigma): fu.log("start processing block %i" % block_id) block = blocking.getBlock(block_id) bb = vu.block_to_bb(block) # get the mask and check if we have any pixels in_mask = mask[bb].astype('bool') if np.sum(in_mask) == 0: fu.log_block_success(block_id) return 0 bb = vu.block_to_bb(block) if channel is None: input_ = ds_in[bb] else: channel_ = [channel] if isinstance(channel, int) else channel in_shape = (len(channel_),) + tuple(b.stop - b.start for b in bb) input_ = np.zeros(in_shape, dtype=ds_in.dtype) for chan_id, chan in enumerate(channel_): bb_inp = (slice(chan, chan + 1),) + bb input_[chan_id] = ds_in[bb_inp].squeeze() input_ = np.mean(input_, axis=0) input_ = vu.normalize(input_) if sigma > 0: input_ = vu.apply_filter(input_, 'gaussianSmoothing', sigma) input_ = vu.normalize(input_) if threshold_mode == 'greater': input_ = input_ > threshold elif threshold_mode == 'less': input_ = input_ < threshold elif threshold_mode == 'equal': input_ = input_ == threshold else: raise RuntimeError("Thresholding Mode %s not supported" % threshold_mode) input_[np.logical_not(in_mask)] = 0 if np.sum(input_) == 0: fu.log_block_success(block_id) return 0 components = label(input_) ds_out[bb] = components fu.log_block_success(block_id) return int(components.max()) + 1
def _accumulate_filter(input_, graph, labels, bb_local, filter_name, sigma, ignore_label, with_size, apply_in_2d): response = vu.apply_filter(input_, filter_name, sigma, apply_in_2d=apply_in_2d)[bb_local] if response.ndim == 4: n_chan = response.shape[-1] assert response.shape[:-1] == labels.shape return np.concatenate([ ndist.accumulateInput(graph, response[..., c], labels, ignore_label, with_size and c == n_chan - 1, response[..., c].min(), response[..., c].max()) for c in range(n_chan) ], axis=1) else: assert response.shape == labels.shape return ndist.accumulateInput(graph, response, labels, ignore_label, with_size, response.min(), response.max())
def _apply_watershed_with_seeds(input_, dt, offset, initial_seeds, config, mask=None): apply_2d = config.get('apply_ws_2d', True) sigma_seeds = config.get('sigma_seeds', 2.) size_filter = config.get('size_filter', 25) sigma_weights = config.get('sigma_weights', 2.) alpha = config.get('alpha', 0.2) # apply the watersheds in 2d if apply_2d: ws = np.zeros_like(input_, dtype='uint64') for z in range(ws.shape[0]): # smooth the distance transform if specified dtz = vu.apply_filter(dt[z], 'gaussianSmoothing', sigma_seeds) if sigma_seeds != 0 else dt[z] # get the initial seeds for this slice # and a mask for the inital seeds initial_seeds_z = initial_seeds[z] initial_seed_mask = initial_seeds_z != 0 # don't place maxima at initial seeds dtz[initial_seed_mask] = 0 seeds = vigra.analysis.localMaxima(dtz, marker=np.nan, allowAtBorder=True, allowPlateaus=True) seeds = vigra.analysis.labelImageWithBackground(np.isnan(seeds).view('uint8')) # remove seeds in mask if mask is not None: seeds[mask[z]] = 0 # add offset to seeds seeds[seeds != 0] += offset # add initial seeds seeds[initial_seed_mask] = initial_seeds_z[initial_seed_mask] # we need to remap the seeds consecutively, because vigra # watersheds can only handle uint32 seeds, and we WILL overflow uint32 seeds, _, old_to_new = vigra.analysis.relabelConsecutive(seeds, start_label=1, keep_zeros=True) new_to_old = {new: old for old, new in old_to_new.items()} # run watershed hmap = _make_hmap(input_[z], dtz, alpha, sigma_weights) wsz, max_id = vu.watershed(hmap, seeds=seeds, size_filter=size_filter, exclude=initial_seeds_z) # mask the result if we have a mask if mask is not None: wsz[mask[z]] = 0 inv_mask = np.logical_not(mask[z]) # NOTE we might not have any pixels in mask for 2d slice max_id = int(wsz[inv_mask].max()) if inv_mask.sum() > 0 else 0 # increase the offset offset += max_id # map back to original ids wsz = nt.takeDict(new_to_old, wsz) ws[z] = wsz # return ws # apply the watersheds in 3d else: if sigma_seeds != 0: dt = vu.apply_filter(dt, 'gaussianSmoothing', sigma_seeds) # find seeds seeds = vigra.analysis.localMaxima3D(dt, marker=np.nan, allowAtBorder=True, allowPlateaus=True) seeds = vigra.analysis.labelVolumeWithBackground(np.isnan(seeds).view('uint8')) # remove seeds in mask if mask is not None: seeds[mask] = 0 seeds[seeds != 0] += offset # add the initial seeds initial_seed_mask = initial_seeds != 0 seeds[initial_seed_mask] = initial_seeds[initial_seed_mask] # we need to remap the seeds consecutively, because vigra # watersheds can only handle uint32 seeds, and we WILL overflow uint32 seeds, _, old_to_new = vigra.analysis.relabelConsecutive(seeds, start_label=1, keep_zeros=True) new_to_old = {new: old for old, new in old_to_new.items()} # run watershed initial_seed_ids = np.unique(initial_seeds[initial_seed_mask]) hmap = _make_hmap(input_, dt, alpha, sigma_weights) ws, max_id = vu.watershed(hmap, seeds=seeds, size_filter=size_filter, exclude=initial_seed_ids) ws = nt.takeDict(new_to_old, ws) if mask is not None: ws[mask] = 0 return ws