https://github.com/dask/dask-image/
conda install -c conda-forge dask-image
pip install dask-image
Latest release includes GPU support for the modules:
Still to do: ndfourier, ndmeasure, ndmorph*
*Done, pending cupy PR #3907
Architecture | Time |
---|---|
Single CPU Core | 2hr 39min |
Forty CPU Cores | 11min 30s |
One GPU | 1min 37s |
Eight GPUs | 19s |
https://blog.dask.org/2019/01/03/dask-array-gpus-first-steps
%gui qt
We used image set BBBC039v1 Caicedo et al. 2018, available from the Broad Bioimage Benchmark Collection Ljosa et al., Nature Methods, 2012.
from dask_image.imread import imread
images = imread('data/BBBC039/images/*.tif')
# images_on_gpu = imread('data/BBBC039/images/*.tif', arraytype="cupy")
images
Denoising images with a small blur can improve segmentation later on.
from dask_image import ndfilters
smoothed = ndfilters.gaussian_filter(images, sigma=[0, 1, 1])
Pixels below the threshold value are background.
absolute_threshold = smoothed > 160
# Let's have a look at the images
import napari
from napari.utils import nbscreenshot
viewer = napari.Viewer()
viewer.add_image(absolute_threshold)
viewer.add_image(images, contrast_limits=[0, 2000])
nbscreenshot(viewer)
viewer.layers[-1].visible = False
napari.utils.nbscreenshot(viewer)
A better segmentation using local thresholding.
thresh = ndfilters.threshold_local(smoothed, images.chunksize)
threshold_images = smoothed > thresh
# Let's take a look at the images
viewer.add_image(threshold_images)
nbscreenshot(viewer)
These are operations on the shape of a binary image.
A morphological opening operation is an erosion, followed by a dilation.
from dask_image import ndmorph
import numpy as np
structuring_element = np.array([
[[0, 0, 0], [0, 0, 0], [0, 0, 0]],
[[0, 1, 0], [1, 1, 1], [0, 1, 0]],
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]])
binary_images = ndmorph.binary_opening(threshold_images, structure=structuring_element)
Each image has many individual nuclei, so for the sake of time we'll measure a small subset of the data.
from dask_image import ndmeasure
# Create labelled mask
label_images, num_features = ndmeasure.label(binary_images[:3], structuring_element)
index = np.arange(num_features - 1) + 1 # [1, 2, 3, ...num_features]
print("Number of nuclei:", num_features.compute())
# Let's look at the labels
viewer.add_labels(label_images)
viewer.dims.set_point(0, 0)
nbscreenshot(viewer)