Whole brain microscopy analysis

With BrainGlobe and napari

Welcome

Schedule Day 1

  • Introductions (15 mins)
  • Installing BrainGlobe and napari (15 mins)
  • Introduction to Image analysis with napari (60 mins)
  • Introduction to BrainGlobe (60 mins)
  • Lunch break (60 mins)
  • Symposium

Schedule Day 2

  • Introduction to anatomical atlases and common coordinate spaces (60 mins)
  • Introduction to image registration (60 mins)
  • Introduction to template building (30 mins)
  • Lunch break (60 mins)
  • Registering whole brain microscopy images with brainreg (60 mins)
  • Segmenting structures in whole brain microscopy images with brainglobe-segmentation (30 mins)
  • Machine learning for image analysis (60 mins)

Schedule Day 3

  • Introduction to cell detection in whole brain microscopy images with cellfinder (60 mins)
  • Detecting cells in large 3D images with cellfinder (60 mins)
  • Combining brainreg and cellfinder on the command line with brainmapper (30 mins)
  • Lunch break (60 mins)
  • Visualising data in atlas space with brainrender and brainrender-napari (45 mins)
  • Scripting with brainglobe-heatmap and brainrender (30 mins)
  • Contributing to BrainGlobe (30 mins)
  • Hackathon preparation (45 mins)

Motivation

By the end of the course:

Motivation

Introductions

The instructor team


Alessandro Felder


Igor Tatarnikov


Harry Carey


Saarah Hussain

Mentimeter

Installation

Install napari and BrainGlobe

Everyone

conda activate brainglobe
uv pip install brainglobe

Silicon mac users (additionally)

conda install niftyreg

Double-check installation

Double-check that running

napari

opens a new napari window, with brainglobe plugins available under Plugins.

Image Analysis (with napari)

Adapted from https://github.com/HealthBioscienceIDEAS/microscopy-novice/ (under CC BY 4.0 license)

Why Napari

  • Napari is a graphical user interface
  • All BrainGlobe analysis tools have a napari plugin

Opening Napari

napari
A screenshot of the default Napari user  interface

Opening images

File > Open Files(s), then navigate to calcium imaging folder and open translation1_00001_ce.tif

Napari’s User interface

A screenshot of Napari with the main user  interface sections labelled

Canvas

Try moving around the image with the following commands:

Pan - Click and drag
Zoom - Scroll in/out
A screenshot of a some fluorescent cells, closer up than before.

Dimension sliders

Closeup of Napari's dimension slider with labels

Three screenshots of the cells image in napari, at  different z depths Three screenshots of the cells image in napari, at  different z depths Three screenshots of the cells image in napari, at  different z depths

Viewer buttons

The viewer buttons (the row of buttons at the bottom left of Napari) control various aspects of the Napari viewer:

  • Console A screenshot of Napari's console button

  • 2D/3D A screenshot of Napari's 2D button / A screenshot of Napari's 3D button

  • Roll dimensions A screenshot of Napari's roll dimensions button

  • Transpose dimensions A screenshot of Napari's transpose dimensions button

  • Grid A screenshot of Napari's grid button

  • Home A screenshot of Napari's home button

A screenshot of a some fluorescent cells

Layer list

A screenshot of a some fluorescent cells

Layer controls

This area shows controls only for the currently selected layer (i.e. the one that is highlighted in blue in the layer list).

  • Opacity
  • Contrast limits

A screenshot of a some fluorescent cells

Layer buttons

Create and remove.

  • Points A screenshot of Napari's point layer button

  • Shapes A screenshot of Napari's shape layer button

  • Labels A screenshot of Napari's labels layer button

  • Remove layer A screenshot of Napari's delete layer button

A screenshot of a some fluorescent cells

Other layer types

Note that there are some layer types that can’t be added via clicking buttons in the user interface, like

These require calling python commands in Napari’s console or an external python script.

Key points

  • Napari’s user interface is split into a few main sections including the canvas, layer list, layer controls…
  • Layers can be of different types e.g. Image, Point, Label
  • Different layer types have different layer controls

A deeper look

File > Open Files(s), then navigate to calcium imaging folder and open translation1_00001_ce.tif (or other small-ish sample data of choice)

A screenshot of a some fluorescent cells

Pixels

A screenshot of Napari - with the mouse cursor  hovering over a pixel and highlighting the corresponding pixel value

Images are arrays of numbers

Open Napari’s built-in console A screenshot of Napari's console button and run:

# Get the image data for the first layer in Napari
image = viewer.layers[0].data

# Print the image values and type
print(image)
print(type(image))

A screenshot of Napari's console

Image dimensions

We can find out the dimensions by running the following in Napari’s console:

image.shape

A screenshot of Napari's console

Image data type

The other key feature of an image array is its ‘data type’ - this controls which values can be stored inside of it.

image.dtype.name

The data type consists of type and bit-depth.

A screenshot of Napari's console

Type

The type determines what kind of values can be stored in the array, for example:

  • Unsigned integer: positive whole numbers
  • Signed integer: positive and negative whole numbers
  • Float: positive and negative numbers with a decimal point e.g. 3.14

Bit depth

The bit depth determines the range of values that can be stored e.g. only values between 0 and \(2^{16}-1\).

print(image.min())
print(image.max())

Common data types

NumPy supports a very wide range of data types, but there are a few that are most common for image data:

NumPy datatype Full name Range of values
uint8 Unsigned integer 8-bit 0…255
uint16 Unsigned integer 16-bit 0…65535
float32 Float 32-bit \(-3.4 \times 10^{38}...+3.4 \times 10^{38}\)
float64 Float 64-bit \(-1.7 \times 10^{308}...+1.7 \times 10^{308}\)

uint8 and uint16 are most common for images from light microscopes. float32 and float64 are common during image processing.

Coordinate system

Diagram comparing a standard graph  coordinate system (left) and the image coordinate system (right) A diagram showing how pixel coordinates change over a simple 4x4 image

  • For 2d images, y is the first coordinate
  • For 3d images, z is the first coordinate

Handedness of the coordinate system

  • napari v0.6.0 and later use a right-handed 3D coordinate system by default.
  • Some BrainGlobe tools (in particular brainrender) expect a left-handed system.

To change to a left-handed system:

  1. Right-click the Toggle 2D/3D view button in the bottom-left corner.
  2. Select the pre-0.6.0 default: away, down, right.

https://napari.org/stable/guides/axis-names.html

Axis names

  • napari v0.7.0 and later use a negative numbers as axis names by default.
    • think of it like Python indexing: in a 3D image, index 0 is index -3.

Visualise the origin and axis direction with View > Axes > Axes visible

Demo: handedness and axis names

Key points

  • Digital images are made of pixels
  • Digital images store these pixels as arrays of numbers
  • Napari (and Python more widely) use NumPy arrays to store images - these have a shape and dtype
  • Most images are 8-bit or 16-bit unsigned integer
  • Images use a coordinate system with (0,0) at the top left, x increasing to the right, and y increasing down

BrainGlobe conventions (for reference)

  • BrainGlobe’s napari plugins work in pixel coordinates (for now)
  • brainrender displays in a left-handed coordinate system
    • this can look like a LR flip bug

Processing images

Now we understand what an image is, and how to look at it in napari, we can start measuring things! But we need to find (“segment”) “things” first!

A screenshot of a some fluorescent cells

Reduce noise with a median filter

from scipy.signal import medfilt2d
image = viewer.layers[0].data
filtered = medfilt2d(image)
viewer.add_image(filtered)
A median-filtered version of the example image

Isolate neurons with a threshold

Example of “semantic” segmentation

thresholded = filtered > 8000 # True or False array
viewer.add_image(thresholded)
A thresholded version of the example image

Label each neuron with a number

Example of “instance” segmentation

from skimage.measure import regionprops, label
labelled = label(thresholded)
viewer.add_labels(labelled)
A labelled version of the example image

Pixels in each neuron

properties = regionprops(labelled)
pixels_in_each_region = [prop.area for prop in properties]
print(pixels_in_each_region)
A list of pixel counts for each region of the example image

Key points

  • Segmentation can be broadly split into ‘semantic segmentation’ (e.g. neuron vs background) and ‘instance segmentation’ (e.g. individual neuron).
  • Segmentations are represented in the computer in the same way as images, but pixels represent an abstraction, rather than light intensity.
  • Napari uses “Labels” layers for segmentations.
  • Segmentation is helpful for analysis.

BrainGlobe

Background

Our goal at the BrainGlobe Initiative is to accelerate progress in neuroscience by providing a set of interoperable tools – and building a community – for computational neuroanatomy.

Understanding the brain

Understanding the brain

Understanding the brain

Brain atlases

Brain atlases

Template

Annotation

Histology

Histology

Serial two-photon tomography

Serial two-photon tomography

Serial two-photon tomography

Light sheet fluorescence microscopy

3D atlases

Alignment

What was needed?

A platform that enabled the community to:

  1. Build tools for whole-brain microscopy data analysis.
  2. Work with multiple species and atlases.
  3. Collaborate with each other.

The BrainGlobe Initiative

BrainGlobe Initiative

Established 2020 with three aims:

  1. Develop general-purpose tools to help others build interoperable software for computational neuroanatomy.
  2. Develop specialist software for specific analysis and visualisation needs.
  3. Reduce barriers of entry, and facilitate the building of an ecosystem of computational neuroanatomy tools.

BrainGlobe Initiative


Open source and community driven


Modular tools that work together

BrainGlobe Initiative

BrainGlobe tools

BrainGlobe atlases

Problem - the data analysis tools are fragmented

  • Model species
  • Imaging modality
  • Anatomical focus
  • Developmental stage

Luigi Petrucco
Federico Claudi
Adam Tyson

BrainGlobe atlases

brainglobe-atlasapi

Luigi Petrucco
Federico Claudi
Adam Tyson

BrainGlobe atlases

Template

Annotation

BrainGlobe atlases


Allen Mouse Brain CCF

Based on serial two-photon tomography


Enhanced and Unified Mouse Brain Atlas

Based on serial two-photon tomography

Luigi Petrucco
Federico Claudi
Adam Tyson

BrainGlobe atlases


Allen Mouse Brain CCF

Based on serial two-photon tomography


Gubra Multimodal 3D Mouse Brain Atlas

Based on light-sheet fluorescence microscopy

Luigi Petrucco
Federico Claudi
Adam Tyson

BrainGlobe atlases

DevCCF

Developmental Mouse Brain Atlas

Luigi Petrucco
Federico Claudi
Adam Tyson

BrainGlobe atlases

Axolotl (Ambystoma mexicanum)

Eurasian Blackcap (Sylvia atricapilla)

Dwarf Cuttlefish (Sepia bandensis)

Prairie Vole (Microtus ochrogaster)

Whole-brain registration

brainreg

Allen Mouse
Brain Atlas

Enhanced and
Unified Mouse
Brain Atlas

Christian Niedwork
Charly Rousseau
Adam Tyson

Spatial analysis

brainglobe-segmentation

Mateo Vélez-Fort
Charly Rousseau
Adam Tyson

3D cell detection

cellfinder

Christian Niedwork
Charly Rousseau
Adam Tyson

3D cell detection

cellfinder

Christian Niedwork
Charly Rousseau
Adam Tyson

3D cell detection

brainmapper

Christian Niedwork
Charly Rousseau
Adam Tyson

3D cell detection

structure_name left_cell_count right_cell_count total_cells
Primary visual area, layer 2/3964.01.0965.0
Primary visual area, layer 5644.06.0650.0
Dorsal part of the lateral geniculate complex, core371.00.0371.0
Lateral posterior nucleus of the thalamus240.00.0240.0
Primary visual area, layer 4207.00.0207.0
Retrosplenial area, ventral part, layer 5162.00.0162.0
Dorsal part of the lateral geniculate complex, shell122.00.0122.0
Lateral dorsal nucleus of thalamus121.01.0122.0
Retrosplenial area, dorsal part, layer 5110.00.0110.0
Retrosplenial area, dorsal part, layer 6a89.00.089.0
(649 more rows not shown)

Visualisation

brainrender

Federico Claudi
Luigi Petrucco
Adam Tyson

Expanding access

More atlases

Atlas Name Species Data Available BrainGlobe
1 Allen Mouse Common Coordinate Framework Mouse
2 Max Planck Zebrafish Brain Atlas Zebrafish
3 Duke Rat Atlas Rat
4 Canary Brain Atlas Canary
5 Population Based Ferret Brain Atlas Ferret
6 Normal Feline Brain atlas Cat
... ... ... ... ...
168 Tawny Dragon Lizard Brain Atlas Tawny Dragon
169 Squirrel Monkey Brain atlas Squirrel Monkey
171 Pigeon Brain Atlas Pigeon

Harry Carey
Alessandro Felder
Adam Tyson

Consistent user experience

brainrender-napari

Alessandro Felder
Adam Tyson

Support for more data types

brainglobe-registration

Igor Tatarnikov
Adam Tyson

Building novel atlases

brainglobe-template-builder

Simon Weiler
Dinora Abdulazhanova
Niko Sirmpilatze
Alessandro Felder
Adam Tyson

Building novel atlases

brainglobe-template-builder

Simon Weiler
Dinora Abdulazhanova
Niko Sirmpilatze
Alessandro Felder
Adam Tyson

BrainGlobe tools


Image Registration

Outline

  • What is image registration
  • Types of registration
  • Transformation types
  • Similarity metrics
  • Optimisation
  • brainreg

Correcting motion

As acquired

After motion correction

Atlas registration

Your sample

The atlas

Atlas registration

sample · atlas · both

Vocabulary

  • Fixed image - the image that doesn’t move
  • Moving image - the image that is being aligned
  • Transformation - the alignment instructions
  • Interest points / landmarks - features used for matching

What is registration?

Registration is the process of aligning two or more images.

To setup a registration problem, we need to define:

  1. What are we matching? — interest points, or pixels
  2. How is the image allowed to move? — defining the transformation type
  3. How do we score a match? — a numerical way of representing how well the images are aligned

Types of registration

Points vs pixels

Point-based (landmark) registration

  • Uses a sparse set of corresponding landmarks
    • Fiducial markers
    • Anatomical landmarks
    • Detected features (e.g. nuclei centroids)

Pixel-based (intensity)

  • Uses the full grid of intensity values
  • No manual point-picking
  • Uses the available texture

Transformation Types

How is the image allowed to move?

Linear vs Non-linear transforms

  • Linear transforms — the whole image moves as a single rigid sheet
    • Parameterized by a small number of degrees of freedom
    • Translation, rotation, scaling, shear
  • Non-linear transforms — different parts of the image can move independently
    • Parameterized by a large number of degrees of freedom
    • Can capture local tissue stretching, tearing, and compression

Linear: rigid

  • Translation + rotation only
  • Distances and angles preserved; nothing stretches

Linear: similarity

  • Rigid and one uniform scale factor
  • Same zoom in all directions

Linear: affine

  • Adds shear and independent per-axis scaling
  • Parallel lines stay parallel, but shapes can skew and stretch unevenly

Linear vs Non-linear transforms

Reminder:

  • Linear transforms — the whole image moves as a single rigid sheet
    • Parameterized by a small number of degrees of freedom
    • Translation, rotation, scaling, shear
  • Non-linear transforms — different parts of the image can move independently
    • Parameterized by a large number of degrees of freedom
    • Can capture local tissue stretching, tearing, and compression

Non-linear

Non-linear: types

  • Thin-plate spline (TPS)
    • Given landmark pairs, finds the smoothest deformation
    • Interpolates smoothly in between the points
  • B-spline
    • A coarse grid of control points where each deforms the nearby region
    • Grid spacing controls flexibility
  • Diffeomorphic (ANTs SyN)
    • Image can bend and stretch, but cannot tear, fold over itself, or collapse to a point

TPS vs B-spline

Similarity Metrics

How can we tell images are aligned?

Similarity metrics

  • A numerical score of how well two images or sets of points match
  • Typically higher is better
  • Once you have a similarity metric, optimisation is possible!

You will also see these called loss, cost, or objective functions — those count errors, so they run the other way up. Same information, opposite sign.

Negative mean squared error

  • Mean squared error (MSE)
    • Mean of the squared differences between corresponding pixels
  • That sum counts error, so we flip its sign and use -MSE
    • A perfect match scores 0 — the best you can do; anything worse is negative
  • Best used when the two images are directly comparable
    • Same stain, same modality, same exposure, same contrast

Negative mean squared error

Cross-correlation

  • Measures how well the two images co-vary — do changes in intensity correlate between the two images?
  • A perfect match has a correlation of 1; smaller numbers are worse
  • More forgiving than -MSE about overall brightness

Cross-correlation

Mutual information

  • Measures how much information about one image is gained by knowing the other
  • A perfect match has a high MI; smaller numbers are worse
  • Works even when the two images have very different brightness/contrast scales

Comparing the three

Point-based distance

  • Measures the distance between corresponding landmarks in the two images
  • Negated for the same reason MSE was — a perfect match scores 0, and every landmark that misses pulls the score down
  • Simple, interpretable, with easy units (µm, pixels)
  • Only measures the alignment at the landmarks themselves, not in between

Cheat sheet: which metric to use

Your situation Reach for
Same stain / same modality -MSE or cross-correlation
Different stains / different modalities Mutual information
Sparse identifiable landmarks Point-based distance

Similarity metric optimisation

Nudging the transformation to raise the score

Iterative optimisation

The general loop for iterative optimisation is

  1. Try a transformation
  2. Measure the score
  3. Nudge the transformation to raise the score
  4. Back to one until it stops improving

Getting stuck: local optima

  • The optimiser only feels the slope directly beneath it
  • So it settles on the first hilltop it reaches — not necessarily the highest
  • The result can look plausible while being aligned to the wrong structure
  • Written as a loss instead of a score, the same trap is called a local minimum

What leaves you on the wrong hilltop

  • Poor starting position (images begin far apart)
  • Repetitive structure — regular tissue patterns, grid-like cell arrays, tiled acquisitions
  • Can be mitigated by starting coarse and refining

Local optima

Phase correlation

For pure translation, we can compute the correlation between two images for every possible shift at once using the Fast Fourier Transform. Usually called phase correlation.

Phase correlation

  1. Transform both images into frequency space
  2. Combine them with a simple multiplication which gives a normalised correlation in frequency space
  3. Transform back
  4. The location of the peak directly tells you the best-aligning shift

Phase correlation

  • No starting guess, no iteration, global solution
  • Fast, and the same cost whatever the shift turns out to be
  • Only works for pure translation
    • Rotation, scaling, or warping still needs the iterative route
  • A good way to get a coarse starting position for that iterative route

Overfitting and Underfitting in Registration

Too much of a good thing

Overfitting and underfitting

  • The same trade-off as fitting a curve to noisy measurements
    • A straight line through curved data misses the real trend: underfitting
    • A high-order polynomial through every point chases the noise: overfitting
  • Registration has both failure modes, in two (or three) dimensions
  • The “model complexity” knob is the transformation type

Underfitting: too many constraints

  • The transformation is too simple to express the real difference between the images
  • Example: rigid registration of sections that were genuinely stretched and torn unevenly during processing
  • Symptom: structured misalignment in part of the image, and optimising harder doesn’t help — the transform cannot express the deformation you need

Underfitting: too many constraints

A non-linear warp, fitted with an affine transform — the global stretch comes out, the local warping cannot, and the score flattens out well below zero.

Overfitting: too few constraints

  • So many degrees of freedom that any two images can be forced to match
    • A dense B-spline grid with more control points than the texture can constrain
  • The score looks excellent, but the tissue is folded, implausibly stretched, or matched to structures that shouldn’t correspond at all

Overfitting: too few constraints

Finding the right level

The right amount of flexibility depends on how much true deformation you expect, and how much data — landmarks, texture — you have to constrain it.

  • Start coarse and refine — rigid -> affine -> non-linear
  • Adjust the regularisation terms
    • Each non-linear method has a way to penalise implausible warps
  • Use a pyramid / multi-resolution approach

brainreg

brainreg

  • Pixel-based — no landmarks to pick
  • Mutual information — sample and atlas are different modalities
  • Affine first, then non-linear (B-spline) — coarse to fine
  • Solves on downsampled data, then applies the result to the full-resolution channels

brainreg: the essentials

  • Atlas — the target atlas
  • Data orientation — e.g. psl, the position of pixel (0, 0, 0)
  • Brain geometry — a whole brain, or a single hemisphere
  • Voxel size — in microns, one per axis, in the same order as the data

Additional channels have no field of their own — open them as extra layers in napari and they are carried through the same transformation.

brainreg: advanced

  • Affine / freeform downsampling steps calculate — how many levels the coarse-to-fine pyramid builds
    • and … steps use — how many of those levels it actually registers on
  • Grid spacing — B-spline control point spacing; tighter grid, more local flexibility, more overfitting risk
  • Bending energy weight — the regularisation term; how hard implausible warps are penalised
  • Smoothing sigma image / atlas — blur before matching, so the optimiser sees shape rather than speckle
  • Histogram bins image / atlas — how finely mutual information bins intensities before scoring

The defaults are tuned for whole mouse brains

brainreg: tips

  • Get the orientation and voxel spacing right first
  • Registration accuracy is the limiting factor, not the resolution of the atlas (typically!)
    • 25 um is usually sufficient for whole-brain registration
  • Always inspect the result, don’t just trust that it finished
    • Check the atlas boundaries against real anatomy
    • Focus on your region of interest

Questions?

Tutorials

Tutorials

  • Registering whole-brain microscopy to an atlas
  • Segmenting probes and bulk fluorescence
  • Cell detection in whole-brain microscopy
    • Retraining cellfinder to fine-tune cell detection
  • Combining registration and cell detection
  • Scripting with BrainGlobe

Data

  • Small sample data comes with napari
  • Large sample data brainglobe-course-data/MS_cx_left
    • on HD: share if needed

Quick excursion into BrainGlobe orientation

  • three letters define position of pixel (0,0,0)
  • e.g. psl - pixel (0,0,0) is Posterior, Superior, Left
  • all BrainGlobe atlases are asr
  • to verify: open data in napari and scroll through data
    • demo

Registering whole brain microscopy images with brainreg

Tutorial

BrainGlobe template builder

Making atlases from scratch

Context

  • Systems neuroscience benefits from more diverse model species
  • These need an anatomical atlas to fully realise this potential
  • BrainGlobe lends itself well to this, thanks to the Atlas API

Context

High-quality, openly licensed atlases exist

  • for some non-traditional model organisms
  • but not for others

Blind Mexican cavefish

If a high-quality, openly licensed atlases exists, we can package it for BrainGlobe.

Rob Kozol (St. John’s University)

Eurasian blackcap

If no atlas exists, it can be made from scratch.

Eurasian blackcap

BrainGlobe template builder

Provide an accessible Python API to democratise template generation, building on existing tools.

Existing tools for template building from (human) neuroimaging

SyGN algorithm

“Symmetric group-wise normalisation”

Basically

  • register all images
  • average
  • repeat


A diagram showing the SyN algorithm

SyGN algorithm

“Symmetric group-wise normalisation”

Coronal slices of the template as the SyGN goes through its steps

Python API

brainglobe-template-builder

from brainglobe_template_builder.preprocess import preprocess
from brainglobe_template_builder.standardis import standardise

Python functions for preparing whole-brain microscopy images for template generation.

  • Built-in quality control at various steps
  • Some initial napari functionality
  • A configuration file for running template building on HPC.

Keep species/atlas-specific code light

atlas-forge

For example, see the scripts for the fiddler crab

Demo

The difficult part is annotation

We are trying to help by

  • writing guides
  • (smoothing functionality)

but we have to rely on expert anatomists.

Finished templates

  • Eurasian blackcap (STPT)
  • Female Lister Hooded rat (STPT)
  • African mole-rat (LSFM)
  • Drosophila wing-disc at instar3 (developmental biology, confocal)

Planned templates

  • Zebrafinch
  • Various Mouse strains
  • Crab
  • Bat
  • Poison frog
  • Swordtail fish

Templates on the “list”

  • Budgerigar?
  • Fiddler ray?
  • Mouse bone?
  • Atlas of the developing fruit fly wing?
  • Singing mouse?

What’s next for template building?

  • GPU acceleration?
  • Provision as a service?
  • Polish the graphical user interface?

Collaboration days

Anyone interested in

  • Trying out annotation tools (e.g. brainbox, microdraw)
  • Making a template with your data

please open an issue describing your thoughts and tag @alessandrofelder in it :)

Segmenting structures in whole brain microscopy images with brainglobe-segmentation

Tutorial (1D)

Tutorial (2D/3D)

Machine learning for image analysis

What we’ll cover

  • Basics of neural networks
  • CNNs
  • U-Nets
  • Visual Transformations
  • Tool landscape

Rule based detection

How would you identify where the cells are in this image?

Rule based detection

Adding a second measurement, like cell size, lets you separate cells from noise

Fitting the boundary from data

We can fit a boundary from the data itself, rather than picking a threshold by eye

Logistic regression

Collapse both measurements into a single score, then fit a sigmoid function

score = w₁ · width + w₂ · brightness + b = 0.29 · width + 0.02 · brightness − 7.6

17 px wide, brightness 183 → score +1.0 → cell

3 px wide, brightness 109 → score −4.5 → not a cell

Real data is complex!

No straight boundary can separate these two groups - wherever you put it, it cuts through the wrong points

Fitting complex relationships

Change the question from “is this a cell?” to “is this exactly one cell?”

Fitting complex relationships

Nothing about the target is sigmoid shaped. Add enough single sigmoids, each with its own fitted weight, and the sum can take essentially any shape.

How the weights are found

Relies on having a loss that estimates model performance

What is a neural net?

A combination of units

Every pixel feeds every unit in the first layer, and each unit is the same as the last few slides: a weight per input, a bias, a squash. The ten outputs are: [0, 1, 2, …, 10]

Architecture: wiring the units

  • Fully connected layers: every unit in one layer connects to every unit in the next
  • Convolutional layers: each unit only connects to a small patch of the previous layer
  • Transformer layers: every unit can read every other, but how much it reads each one is computed from the input itself

All of these are just different ways to wire up regression units.

Building your training set

Train, validation, test split

Split the data once, three ways — and treat the test set as spent the moment you look at it.

Memorising practice answers != learning biology.

Test set leakage

Splitting images randomly isn’t the same as splitting subjects randomly

  • If one animal contributes images to both the training set and the test set, the model can partly identify it: same tissue, same staining batch, same imaging session
  • The test score then reflects memorisation of that subject, not real generalisation
  • Fix: split by subject (or by acquisition session) first, then assign every image from that subject to train, validation, or test — never split across

Split the animals, not the images

Statistical not causal

A model learns whatever correlates with the label, which may not necessarily be the biology!

  • Chest X-ray models trained to detect COVID-19 were found to rely on features outside the lungs entirely — image borders, laterality markers, patient positioning
  • If every positive scan came from one hospital, the model can learn that hospital’s scanner artefacts instead of the disease

The model is statistical, not causal. It will happily use a confound if the confound is easier to learn than the real biology.

Scoring a model

Every claim about performance is one number, computed by comparing predictions to labels on one split

  • Accuracy — fraction of calls that were right. Misleading when one class is rare: call everything “background” in a sparse image and you score 99%
  • Precision — of the things you called cells, how many were cells? Low precision = false positives
  • Recall — of the cells that were there, how many did you find? Low recall = false negatives
  • F1 — a combined metric, so a model can’t win by being timid or trigger-happy

Precision and recall trade off: lower the detection threshold and recall goes up while precision goes down

Generalisation

  • A model that generalises scores as well on unseen data as on training data
  • Underfitting: too little capacity, or too little training — poor on both
  • Overfitting: enough capacity to memorise the training set — good on train, poor on test

Test labels are human opinions too. 95% recall against one annotator’s boundaries is not 95% against the biology.

Underfitting

Too little capacity to represent the relationship at all - so it is wrong on the training data as well as on unseen data

Overfitting

Too much capacity, the model memorises the training data without extracting any information

Data augmentation

Labelling is the expensive step: make more training examples out of the ones you already have!

  • Flip, rotate, rescale, brighten, blur, add noise
  • The model sees a sample at more orientations, brightnesses and noise levels
  • Microscopy has no up, so flips and rotations are free

Data augmentation

Augment the training set only

  • Split first, augment second — a flipped copy of a training image landing in the test set is the leakage problem again
  • Validation and test sets stay untouched: they have to look like the data you’ll actually face
  • Augmentation buys invariance, not new biology. 500 copies of 10 animals is still 10 animals!

From pixels to meaning

Pixels don’t scale

784 pixels for a thumbnail digit — a single tile of imaging data is millions. Almost all of it is empty background! The actual information is sparse

The compression funnel

pixel space

millions of numbers, mostly redundant

embedding space

a few hundred numbers, in which like sits near like

Convolutional Neural Networks

A window that slides

  • The same small window of weights is applied everywhere in the image
  • Where it matches, it writes a high value into a feature map

Increasingly abstract spotters

Early layers find edges; later layers combine them into shapes, then parts, then a name

Detection vs segmentation

Detection — a point per cell

Segmentation — every pixel is a cell or background

U-Net: built for segmentation

The U shape

Zoom out for context, zoom back in to trace the exact outline.

Skip connections

Without them the decoder only has the blurry bottleneck to work from.

Input -> precise mask

Scoring a mask: IoU

Precision and recall need a rule for when a predicted cell is a labelled cell. For masks, that rule is overlap.

Vision Transformers

Attention, in words

In “the animal didn’t cross the street because it was too tired”, what does “it” refer to?

Attention, in images

Same idea on pixels: the model decides for itself which parts of the image matter

ViT: patches, like words

  • The image is cut into fixed-size patches, and each patch is treated like a word
  • The stack of patches goes through the same machinery to generate an embedding
  • A simple network on top can use this embedding to predict the output

From scratch vs fine-tuning

Training from scratch

  • Complex model architectures take longer to train and need more data
  • Large foundational models are trained on 100k - 1 billion images!
    • cellfinder was trained on 100k hand labelled cells
  • Generating the data takes too long

Fine-tuning

  • Starting from random weights doesn’t always make sense!
  • Sometimes you want to reuse the encoder/embeddings from other models
  • Feed a small number (100s to 1000s) of your data to teach the model “your” data

Human-in-the-loop

Most fine-tuning data comes from correcting the model’s own mistakes.

The tool landscape

ilastik

Learning, without deep learning

  • You paint a few pixels of your target and a few of background
  • A classical classifier (random forest) learns the boundary between them
  • Interactive: you see the result and paint more where it’s wrong

StarDist

A shape prior instead of free-form pixels

  • Predicts, for each pixel, the distances to the object boundary along fixed rays — a star-convex polygon
  • Because every cell is one polygon, touching cells come out as separate objects rather than one merged blob

Cellpose 2

A U-Net that predicts flows, plus retraining in the loop

  • Instead of a mask, it predicts for each pixel a direction pointing towards its cell’s centre; pixels that flow to the same point are one cell
  • Generalist model trained on a large, deliberately varied collection of cell images
  • Ships with human-in-the-loop retraining: correct a few cells, fine-tune, carry on

Segment Anything (SAM)

The foundation-model move: one model, fine-tuned

  • ViT backbone, trained on SA-1B: ~11 million natural images, ~1 billion masks — of which only ~10 million over ~300k images were drawn by hand; the rest the model generated and a filter kept
  • Promptable: click a point or drag a box, get a mask — no retraining
  • Knows “object”, not “cell”, out of the box it does poorly on microscopy images

Cellpose-SAM

Fine-tuning a foundation model onto cells

  • Takes SAM’s pretrained ViT backbone and trains it on Cellpose’s cellular datasets
  • Deliberately trained against realistic degradations — blur, noise, anisotropy, channel order — so it holds up on data it hasn’t seen
  • Approaches human-to-human agreement on their test set

cellfinder

Detection for large 3D imaging datasets

  • Classical filtering proposes candidate cells; a small CNN classifies each candidate as cell or artefact
  • Detection, not segmentation: counts and coordinates not outlines
  • Ships with a pretrained network, which can (should!) be fine-tuned

Tomorrow

Tomorrow you’ll retrain cellfinder on your own corrections — fine-tuning and human-in-the-loop, on real data.

Questions?

Cell detection with cellfinder

3D Cell Detection

cellfinder

cellfinder is the BrainGlobe tool for detecting cells

It finds centre coordinates of fluorescently labelled cells (bright spots of given size)

Applications

  • Viral tracing in mice
  • cFos-staining experiments (experimental support)
  • Maybe others?

Serial two-photon tomography

Light sheet fluorescence microscopy

cellfinder input data

cellfinder input data

cellfinder input data

Whole brain microscopy, two channels

signal

background

cellfinder input data

Whole brain microscopy, two channels

signal

background

Why is 3D cell detection hard?

Classical image processing lacks sweet spot in noisy 3d microscopy.

Low threshold (2’000)

High threshold (10’000)

Why is 3D cell detection hard?

Classical image processing lacks sweet spot in noisy 3d microscopy.

Low threshold (2’000)

High threshold (10’000)

Why is 3D cell detection hard?

Pure machine-learning based methods are slow on such large data (~100GB per channel)

cellfinder strategy

Best of both worlds

  • Select too many possible cells: “candidates”
  • Use machine-learning to classify candidates
    • binary classification: cell/not cell
    • needs curation and re-training

Cell candidate detction

Christian Niedwork
Charly Rousseau
Adam Tyson

Cell candidate detction

Christian Niedwork
Charly Rousseau
Adam Tyson

Cell candidate classification

Christian Niedwork
Charly Rousseau
Adam Tyson

Cellfinder high-level user workflow

%%{init: {'theme': 'default', 'flowchart': {'curve': 'basis'}}}%%
flowchart LR
    A[1. Detect<br/>Candidates] --> B[2. Classify<br/>Candidates]
    B --> C[3. Curate<br/>Candidates]
    C --> D[4. Retrain<br/>Model]
    D --> B
    B -.->|Further Analysis & Visualisation| E[ ]
    style E fill:transparent,stroke:transparent
    D ~~~ E

cell detection = candidate detection + candidate classification

cellfinder candidate detection

A series of image filters on the signal channel only

  1. 2D filter
  2. 3D filter
  3. Structure splitting

2D filter

1. (Clip to reserve 2 values)

2. Keep bright enought tiles

3. Enhance peaks

a) median filter

b) gaussian filter

c) laplacian filter

4. Threshold

2D Filtering parameters

Parameter Default Description
log_sigma_size 0.2 Gaussian filter width (as a fraction of soma diameter) used during 2d in-plane Laplacian of Gaussian filtering.
soma_diameter 16 The expected in-plane (xy) soma diameter (microns).
n_sds_above_mean_thresh 10 Per-plane intensity threshold (the number of standard deviations above the mean) of the filtered 2d planes used to mark pixels as foreground or background.

3d filter + structure splitting

1. Looks at sphere (ellipsoid) around each pixel

a) If sufficient pixels in the ellipsoid are bright, mark as part of candidate

2. If needed structure is big, split it into several.

3. Compute and return centres of structures

Structure splitting in 3D

3D Filtering parameters

Parameter Default Description
ball_xy_size 6 3d filter’s in-plane (xy) filter ball size (microns).
ball_z_size 15 3d filter’s axial (z) filter ball size (microns).
ball_overlap_fraction 0.6 3d filter’s fraction of the ball filter needed to be filled by foreground voxels, centered on a voxel, to retain the voxel.

Splitting parameters

Parameter Default Description
split_ball_xy_size 6 Similar to ball_xy_size, except the value to use for the 3d filter during cluster splitting.
split_ball_z_size 15 Similar to ball_z_size, except the value to use for the 3d filter during cluster splitting.
split_ball_overlap_fraction 0.8 Similar to ball_overlap_fraction, except the value to use for the 3d filter during cluster splitting.
n_splitting_iter 10 The number of iterations to run the 3d filtering on a cluster. Each iteration reduces the cluster size by the voxels not retained in the previous iteration.
soma_spread_factor 1.4 Cell spread factor for determining the largest cell volume before splitting up cell clusters. Structures with spherical volume of diameter soma_spread_factor * soma_diameter or less will not be split.
max_cluster_size 100_000 Largest detected cell cluster (in cubic um) where splitting should be attempted. Clusters above this size will be labeled as artifacts.

Candidate coordinates

Store the average coordinate of each candidate.

Classification

Assumption: noise is bright in both channels, signal is bright only in one channel.

signal

background

Classification

Default model, use as starting point for retraining.

  • ResNet, trained on…
  • ~100’000 manual annotations
    • 50,653 cells
    • 56,902 non-cells
    • from 5 brains

Classification parameters

Parameter Default Description
cube_width 50 The width of the data cube centered on the cell used for classification.
cube_height 50 The height of the data cube centered on the cell used for classification.
cube_depth 20 The depth of the data cube centered on the cell used for classification.
network_depth 50 The network depth to use during classification.
normalize_channels False If True, the signal and background data will be each normalized to a mean of zero and standard deviation of 1 before classification.
normalization_n_sampling_planes 50 If normalize_channels is True, the data arrays will be down-sampled in the first axis to use approximately this many planes – equally spaced, before calculating their mean/std. E.g. a value of 50 for a dataset of 200 planes means every fourth plane will be used.
max_workers 3 The max number of sub-processes to use for data loading / processing during classification.

Cell detection tutorial

cell detection tutorial

Fine-tuning detection

Stretch exercise: Fine-tune detection parameters on your data with this experimental napari plugin addition, in a new environment

conda create -n cellfinder-experimental python=3.13
conda activate cellfinder-experimental
uv pip install git+https://github.com/matham/cellfinder@mergedv2
uv pip install napari[all]

Fine-tuning detection

Stretch exercise: Fine-tune detection parameters on your data with this experimental napari plugin addition, in a new environment.

Cellfinder high-level workflow

%%{init: {'theme': 'default', 'flowchart': {'curve': 'basis'}}}%%
flowchart LR
    A[1. Detect<br/>Candidates] --> B[2. Classify<br/>Candidates]
    B --> C[3. Curate<br/>Candidates]
    C --> D[4. Retrain<br/>Model]
    D --> B
    B -.->|Further Analysis & Visualisation| E[ ]
    style E fill:transparent,stroke:transparent
    D ~~~ E

Curation and retraining

Suggested strategy

  • spend hours, not days curating
  • iterate fast: curate, retrain, classify and repeat
  • curated balanced data (equal number of cells/not cells)

Reminder: only candidate cells will be classified

Retraining parameters

Parameter Default Description
trained_model - Path to the trained model
network_depth 50 Resnet depth (based on He et al. (2015)
learning_rate 0.0001 Learning rate for training the model
test_fraction 0.1 Fraction of training data to use for validation
epochs 100 Number of training epochs
no_augment False If True, don’t apply data augmentation
augment_likelihood 0.9 Value [0, 1] with the probability of a data item being augmented. I.e. 0.9 means 90%% of the data will have been augmented.
lr_schedule () If not empty, the list of epochs when to multiply the current learning rate by the lr_multiplier. E.g. if it’s [10, 25], we start with a learning rate of 0.001, and lr_multiplier is 0.1, then the LR will be 0.001 for epochs 0-9, 0.0001 for 10-24, and 0.0001 for epoch 25 and beyond.
lr_multiplier 0.1 The multiplier by which to multiply the previous learning rate at the epochs listed in lr_schedule.
augment_likelihood 0.9 Value [0, 1] with the probability of a data item being augmented. I.e. 0.9 means 90%% of the data will have been augmented.
normalize_channels False Normalize the training data to the mean/std of the datasets from which the cubes came from.

Retraining parameters

Parameter Default Description
continue_training False Continue training from an existing trained model. If no model or model weights are specified, this will continue from the included model.
batch_size 16 Training batch size
tensorboard False Log to output_directory/tensorboard
max_workers 3 Maximum number of worker processes to use to load data
pin_memory True Pins data to be sent to the GPU to the CPU memory. This allows faster GPU data speeds, but can only be used if the data used by the GPU can stay in the CPU RAM while the GPU uses it. I.e. there’s enough RAM. Otherwise, if there’s a risk of the RAM being paged, it shouldn’t be used.

Curation and retraining

Tutorial

Practical notes for users

Similar to other BrainGlobe tools, cellfinder has

  • napari interface (as seen today)
  • Python API

and additionally,

  • part of a command line interface for detection and classification (“brainmapper”)

Interoperability with OME zarr

The Python API enables interoperability with the wider Python ecosystem.

from cellfinder.core import main as cellfinder_run 

# open your OME Zarr image here

cellfinder_run(...)

Interoperability with other tools

The Python API enables interoperability with the wider Python ecosystem.

from cellfinder.core.detect import main as cellfinder_detect

candidates = cellfinder_detect(...)

classify_candidates_custom(candidates, ...)

Example: Biapy + BrainGlobe

Implementation notes

  • implemented within the pytorch framework
  • uses custom multithreading and multiprocessing
    • works particularly well on nvidia GPUs
  • highly optimised data loading

Matt Einhorn, Cleland Lab, Cornell

Performance experiments

What’s next for cellfinder

performance improvements allows new applications

  • viral tracing in rats (bigger images)
  • CFoS applications (more cell candidates)
    • also, support for cell metadata beyond centre (e.g. average intensity / cell)

What’s next for cellfinder

implementations for

  • single channel
  • 2D sections

Soumya

What’s next for cellfinder

longer term

  • classification of different types of cells

Key take-aways

  • cellfinder can be used to efficiently find cells in large whole-brain microscopy images
  • it uses classical image filtering to find candidates and then classifies them
    • candidates can include many false positives, but must include all true positives
    • usually classification model needs curation and retraining

Detecting cells in large 3D images with cellfinder

brainmapper

Combining registration and cell detection

Often we want to combine atlas registration and cell detection, to answer questions like: how many cells are in each brain region?

Anatomical context

Pulling things together: brainmapper CLI

brainmapper CLI

  • Required arguments
    • -s The primary signal channel
    • -b The secondary autofluorescence channel
    • -o The output directory
    • --orientation e.g. psl
    • -v The voxel spacing (microns) in the same order as the data orientation (psl): 5 2 2.
    • --atlas

brainmapper CLI

  • allows batching on HPC
  • flexible: can switch each of registration, detection, classification on and off independently

Performance tricks

  • move data close to compute

Tutorial

BrainMapper napari tutorial

CLI documentation

Tour of other BrainGlobe tools

Analysing cell positions in atlas space

Tutorial

Visualisation of data in atlas space with brainrender-napari

Tutorial (brainrender-napari)

Making heatmaps with brainglobe-heatmap scripts

Task:

  • Visualise the cell density/region of a coronal slice

Example brainglobe-heatmap scripts

Making renders with brainrender scripts

Tasks:

  • Visualise a region in the atlas
  • Visualise the cells from the large sample data
  • (Bonus) Make an animation

Example brainrender scripts

Further user-facing tools

Underlying libraries

How to get help

You are welcome to contribute to BrainGlobe - get in touch anytime and we will support you!

Feedback

Please take 5 minutes to fill out this feedback form!