Search code examples
pythonscikit-imagepython-napari

Adding blobs from blob_dog to a 3D image stack using skimage and napari


I'm trying to use blob log or blog dog for blob detection in a 3D image using skimage. I'm using napari and binary blob (3D) images as a sample (but this will not be the image I will be using later this just has clear-cut blobs). However, I'm having trouble applying the blobs to the image/adding it to the viewer.

Skimage has a 2D image example using matplotlib adding circles to the image, but I would like to use this to identify blobs on the 3D image and create either a binary image (a mask essentially) or labels.

This is what I have, but I'm not sure where to go from here:

from skimage.data import binary_blobs as BBlobs
import pandas as pd
import imageio as io
import numpy as np
import napari  
from skimage import filters, morphology, measure, exposure, segmentation, restoration, feature
import skimage.io as skio
from scipy import ndimage as ndi


def add_to_viewer(layer_name, name):
    viewer.add_image(
        layer_name,
        name = name,
        scale = spacing
    )

bblobs = BBlobs(n_dim=3)
add_to_viewer(bblobs, 'image')

blobs = feature.blob_dog(bblobs)

for blob in blobs:
    z,y,x,area = blob

This is skimage's blob feature detection example.

Any help would be appreciated.


Solution

  • What are you trying to do after? Do you need the blob sizes or only the positions? The answer depends a lot on the question. Here's three answers:

    1. Just visualise the blobs as points:
    viewer.add_points(
        blobs[:, :-1], size=blobs[:, -1], name='points', scale=spacing
    )
    
    1. Ignore the size (assuming e.g. you are doing watershed later, this doesn't matter), create a labels volume with one label per coordinate:
    from skimage.util import label_points
    
    labels = label_points(blobs[:, :-1], bblobs.shape)
    viewer.add_labels(labels, scale=spacing)
    

    Note that label_points relies on the current main branch (unreleased) of scikit-image, but you can just copy the source code in the meantime. scikit-image 0.19 should be released soon after this post with the function.

    1. Make a labels layer and use napari's Labels layer API directly to paint a blob at each point including the size from blob detection:
    labels_layer = viewer.add_labels(
        np.zeros_like(bblobs, dtype=np.int32), name='blobs', scale=spacing
    )
    for i, blob in enumerate(blobs, start=1):
        labels_layer.selected_label = i
        labels_layer.brush_size = blob[-1]
        labels_layer.paint(blob[:-1], refresh=False)
    labels_layer.refresh()
    

    One small caveat in scenarios 1 and 3 is that I think the blobs sizes are "sigmas", meaning that most of the blob is within 2 sigma of the centre, so you might need to multiply all the sizes by 2 to get a nice display.