Skip to content

Fix mitochondria instances coating touching mitochondria - #189

Merged
lufre1 merged 1 commit into
mainfrom
fix-mito-watershed-plateau
Oct 29, 2026
Merged

lufre1 merged 1 commit into
mainfrom
fix-mito-watershed-plateau

Conversation

@lufre1

@lufre1 lufre1 commented Oct 28, 2026

Copy link
Copy Markdown
Contributor

Problem

Sometimes a mitochondrion segmentation forms a thin shell around a neighbouring mitochondrion, along the neighbour's outer membrane. In some tomograms the shell even becomes a separate object of its own.

Cause

In _run_segmentation, the watershed heightmap is the normalized inverse distance to the boundaries (boundaries >= boundary_threshold). That distance is 0 on the whole boundary band, so the band is a plateau where the heightmap is exactly 1.0. The order in which the seeded watershed floods voxels of the same height is unspecified. So once a seed's flood reaches a touching mitochondrion's band, it can spread along the outer layers of that band before the band's own mitochondrion claims them.

Fix

Add the boundary probability to the heightmap so that the band is graded rather than flat. The barrier (boundaries > threshold & foreground < threshold) is still set to the maximum of the heightmap. This is a two-line change.

A tie-break by the distance to the nearest seed (as in vesicles.py) was also tested on top of this. It made no measurable difference, so it is left out.

Results

These are 6 tomograms, rerun from cached mitochondria2 predictions with the default parameters. Measurements are at the model resolution (2.87 nm).

  • contact: the number of voxel faces between different mitochondria instances.
  • max thin: the largest fraction of an instance that a 3-voxel opening removes. Coats are thin, so they show up here.
tomogram objects before → after contact before → after max thin before → after
nav56 6 → 6 0 → 0 0.044 → 0.044
nav60 7 → 7 16 → 12 0.038 → 0.040
nav64 7 → 7 27,926 → 1,089 0.038 → 0.022
nav70 8 → 6 (two objects were 74% and 93% coat) 317,538 → 9,892 0.934 → 0.007
nav91 6 → 6 32,099 → 70 0.190 → 0.043
nav93 9 → 9 57,803 → 8,478 0.127 → 0.127

Instances that don't touch another one are unchanged or nearly so. Segmentations change where mitochondria touch.

Test

TestMitochondriaSegmentation.test_touching_mitochondria in test/test_inference.py runs on synthetic data and needs no network. It uses two balls with overlapping boundary bands. Without the fix, about 19k voxels of one ball (43%) go to the other; with the fix it is under 1%. test_inference.py passes.

🤖 Generated with Claude Code

The heightmap was the normalized inverse distance to the boundaries, which
is a plateau of equal height on the whole boundary band. The flooding order
within one height level is unspecified, so a mitochondrion could flood along
the boundary band of a touching one and "coat" it. Adding the boundary
probability makes the band graded.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@lufre1
lufre1 merged commit 7d8a3bb into main Oct 29, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant