Interactive cropping with napari#

When cropping three-dimensional data it might make sense to do this interactively, e.g. using napari. For scripting convenience, we use a napari plugin, called napari-crop.

See also

import napari
from napari.utils import nbscreenshot
from skimage.io import imread
from magicgui import magicgui

# The following is a private function. The interface 
# may be changed in the future. If you copy that code 
# it breaks at some point, please come back to this  
# notebook and check how to update your code.
from napari_crop._function import crop_region

We start by loading a dataset and showing it in napari.

# Start a napari viewer
viewer = napari.Viewer()

# open an image and store it in a layer
image_layer = viewer.open("../../data/Haase_MRT_tfl3d1.tif")

# select a center plane for viewing
viewer.dims.current_step = [100, 0, 0]

# show napari window as screenshot in the notebook
nbscreenshot(viewer)
C:\Users\rober\Anaconda3\envs\bio_39\lib\site-packages\napari\plugins\_plugin_manager.py:494: UserWarning: Plugin 'napari-accelerated-pixel-and-object-classification' provided a non-callable type to `napari_experimental_provide_function`: <class 'magicgui._magicgui.MagicFactory'>. Function widget ignored.
  warn(message=warn_message)

Next, we put a circle shape in a new shapes layer into the viewer.

def make_circle(circle_center_x, circle_center_y, circle_radius):
    """Helper function to create circles"""
    current_z_slice = viewer.dims.current_step[0]

    return [[current_z_slice, circle_center_y - circle_radius, circle_center_x - circle_radius],
           [current_z_slice, circle_center_y - circle_radius, circle_center_x + circle_radius],
           [current_z_slice, circle_center_y + circle_radius, circle_center_x - circle_radius],
           [current_z_slice, circle_center_y + circle_radius, circle_center_x + circle_radius]]

elipses = make_circle(80, 100, 50)
    
# add shapes to viewer
shapes_layer = viewer.add_shapes(elipses, shape_type='ellipse', edge_width=2)

nbscreenshot(viewer)

Next, we attach a graphical user-interface (GUI) for cropping a region.

# make a graphical user interface
crop_gui = magicgui(crop_region)

# attach it to the viewer window
viewer.window.add_dock_widget(crop_gui)

nbscreenshot(viewer)

After attaching the GUI, we can also click the Run button and crop out a region like this:

crop_gui()

nbscreenshot(viewer)

We can also reposition the circle and crop again.

# reposition the selected circle
elipses = make_circle(120, 150, 50)
shapes_layer.data = elipses

# duplicate last cropped layer, because cropping again would overwrite it
viewer.add_image(viewer.layers[2].data)

# crop again
crop_gui()

# crop one more circle
shapes_layer.data = make_circle(170, 150, 50)
viewer.add_image(viewer.layers[2].data)
crop_gui()

nbscreenshot(viewer)

By the end, we remove the image and shapes layers and take a look at the crops side by side.

# Remove the first two layers
viewer.layers.remove(viewer.layers[0])
viewer.layers.remove(viewer.layers[0])

# toggle grid view
viewer.grid.enabled = True
viewer.grid.stride = 1

nbscreenshot(viewer)