<jupyter_start><jupyter_text>MulticutUse the `elf.segmentation` module for boundary based multicut segmentation: [Multicut brings automated neurite segmentation closer to human performance](https://www.nature.com/articles/nmeth.4151). We use data from the [ISBI 2012 EM Segmentation challenge](http://brainiac2.mit.edu/isbi_challenge/home) and [The Mutex Watershed: Efficent, Parameter-Free Image Partitionong](http://openaccess.thecvf.com/content_ECCV_2018/html/Steffen_Wolf_The_Mutex_Watershed_ECCV_2018_paper.html).You can obtain the example data [here](https://hcicloud.iwr.uni-heidelberg.de/index.php/s/6LuE7nxBN3EFRtL).The boundary based segmentation approach works as follows:1. Predict pixel-wise affinity (or boundary) map. Here, we use pre-computed results for this step.2. Compute a watershed over-segmentation based on the affinity maps.3. Compute the region adjacency graph defined by the watershed over-segmentation.4. Compute weights for the edges of this graph by accumulating the affinity (or boundary) map over the edge pixels.5. Partition the graph based on the edge weights via Multicut and project the result back to the pixel level.  Preparation<jupyter_code>%gui qt5 
import numpy as np

# import napari for data visualisation
import napari

# import the segmentation functionality from elf
import elf.segmentation.multicut as mc
import elf.segmentation.features as feats
import elf.segmentation.watershed as ws

# import the open_file function from elf, which supports opening files
# in hdf5, zarr, n5 or knossos file format
from elf.io import open_file
# read the data
# you can download the example data from here:
# https://hcicloud.iwr.uni-heidelberg.de/index.php/s/6LuE7nxBN3EFRtL
data_path = '/home/pape/Work/data/isbi/isbi_test_volume.h5'  # adjust this path
with open_file(data_path, 'r') as f:
    # load the raw data
    raw = f['raw'][:]
    # load the affinities, we only need the first 3 channels
    affs = f['affinities'][:3, :]
# visualize the raw data and the affinity maps with napari
# TODO switch to new napari syntax
# napari.view_image(raw, name='raw')
# napari.view_image(affs, name='affinities')
viewer = napari.Viewer()
viewer.add_image(raw, name='raw')
viewer.add_image(affs, name='affinities')<jupyter_output><empty_output><jupyter_text>Set up the Multicut problem<jupyter_code># compute watershed over-segmentation based on the affinity maps

# first, we have to make a single channel input map for the watershed,
# which we obtain by averaging the afifnities
boundary_input = np.mean(affs, axis=0)

# next, we run the distance transform watershed.
# the data is very anisotropic, so we apply the watershed in 2d
# and stack the watershed results along z, with the appropriate id offset
watershed = np.zeros_like(boundary_input, dtype='uint64')
offset = 0
for z in range(watershed.shape[0]):
    # the threshold parameter determines at which value the input map is thresholded before applying
    # the distance transform.
    # the parameter sigma_seeds determines how strong the seed map is smoothed before seeds are
    # computed via local minima. This controls the degree of over-segmentation
    wsz, max_id = ws.distance_transform_watershed(boundary_input[z], threshold=.25, sigma_seeds=2.)
    wsz += offset
    offset += max_id
    watershed[z] = wsz
# visualize the watershed result
# TODO switch to new napari syntax
# napari.view_image(raw, name='raw')
# napari.add_labels(watershed, name='watershed')
viewer = napari.Viewer()
viewer.add_image(raw, name='raw')
viewer.add_labels(watershed, name='watershed')
# compute the region adjacency graph
rag = feats.compute_rag(watershed)

# compute the edge costs
# the offsets encode the pixel transition encoded by the 
# individual affinity channels. Here, we only have nearest neighbor transitions
offsets = [[-1, 0, 0], [0, -1, 0], [0, 0, -1]]
costs = feats.compute_affinity_features(rag, affs, offsets)[:, 0]

# 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
edge_sizes = feats.compute_boundary_mean_and_length(rag, boundary_input)[:, 1]
costs = mc.transform_probabilities_to_costs(costs, edge_sizes=edge_sizes)<jupyter_output><empty_output><jupyter_text>Solve the Multicut<jupyter_code># run the multicut partitioning, here, we use the kernighan lin 
# heuristics to solve the problem, introduced in
# http://xilinx.asia/_hdl/4/eda.ee.ucla.edu/EE201A-04Spring/kl.pdf
node_labels = mc.multicut_kernighan_lin(rag, costs)

# map the results back to pixels to obtain the final segmentation
segmentation = feats.project_node_labels_to_pixels(rag, node_labels)
# visualize the segmentation result
# TODO switch to new napari syntax
# napari.view_image(raw, name='raw')
# napari.add_labels(segmentation, name='multicut-segmentation')
viewer = napari.Viewer()
viewer.add_image(raw, name='raw')
viewer.add_labels(segmentation, name='multicut')<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.08780487804878048, 'fraction_numerical': 0.012097560975609756, 'mean_word_length': 5.423558897243108, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 13, 'https://': 3, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '3', 'dir': 'jupyter-structured-clean-dedup', 'id': '265277', 'license': 'MIT', 'n_tokens_mistral': 1668, 'n_tokens_neox': 1563, 'n_words': 544, 'path': 'example/segmentation/multicut.ipynb', 'repo_name': 'boykovdn/elf', 'size': '5125'}