Skip to content

Commit a088c16

Browse files
C-AchardMMathisLab
andauthored
v0.2.1 : Update defaults and new utilities (#98)
* Enable thresholding by default * Update plugin_model_inference.py * Enable window + default thresholds * Update V-O defaults * Add grid search utility * Document grid search util * Fix default threshold on first inference open * Version bump + Wnet3d assumptions docs * Update README.md * Bump to 0.2.1 + typos fixes * Update inference_module_guide.rst * Update inference_module_guide.rst * Update utils_module_guide.rst * Update welcome.rst --------- Co-authored-by: Mackenzie Mathis <mathis@rowland.harvard.edu>
1 parent bee33f5 commit a088c16

18 files changed

+273
-65
lines changed

README.md

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# CellSeg3D: self-supervised (and supervised) 3D cell segmentation, primarily for mesoSPIM data!
1+
# CellSeg3D: self-supervised (and supervised) 3D cell segmentation, primarily for mesoSPIM data!
22
[![napari hub](https://img.shields.io/endpoint?url=https://api.napari-hub.org/shields/napari-cellseg3d)](https://www.napari-hub.org/plugins/napari-cellseg3d)
33
[![PyPI](https://img.shields.io/pypi/v/napari-cellseg3d.svg?color=green)](https://pypi.org/project/napari-cellseg3d)
44
[![Downloads](https://static.pepy.tech/badge/napari-cellseg3d)](https://pepy.tech/project/napari-cellseg3d)
@@ -59,11 +59,17 @@ The strength of our approach is we can match supervised model performance with p
5959

6060
## News
6161

62-
**New version: v0.2.0**
62+
**New version: v0.2.1**
6363

64-
- Changed project name to "napari_cellseg3d" to avoid setuptools deprecation
65-
- Small API changes for training/inference from a script
66-
- Some fixes to WandB integration ad csv saving after training
64+
- v0.2.1:
65+
- Updated plugin default behaviors across the board to be more readily applicable to demo data
66+
- Threshold value in inference is now automatically set by default according to performance on demo data on a per-model basis
67+
- Added a grid search utility to find best thresholds for supervised models
68+
69+
- v0.2.0:
70+
- Changed project name to "napari_cellseg3d" to avoid setuptools deprecation
71+
- Small API changes for training/inference from a script
72+
- Some fixes to WandB integration and csv saving after training
6773

6874
Previous additions:
6975

docs/source/guides/inference_module_guide.rst

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,13 @@ Interface and functionalities
5050

5151
Inference parameters
5252

53-
* **Loading data** :
53+
* **Loading data**:
5454

5555
| When launching the module, select either an **image layer** or an **image folder** containing the 3D volumes you wish to label.
5656
| When loading from folder : All images with the chosen extension ( currently **.tif**) will be labeled.
5757
| Specify an **output folder**, where the labelled results will be saved.
5858
59-
* **Model selection** :
59+
* **Model selection**:
6060

6161
| You can then choose from the listed **models** for inference.
6262
| You may also **load custom weights** rather than the pre-trained ones. Make sure these weights are **compatible** (e.g. produced from the training module for the same model).
@@ -66,19 +66,19 @@ Interface and functionalities
6666
Currently the SegResNet and SwinUNetR models require you to provide the size of the images the model was trained with.
6767
Provided weights use a size of 64, please leave it on the default value if you're not using custom weights.
6868

69-
* **Inference parameters** :
69+
* **Inference parameters**:
7070

7171
* **Window inference**: You can choose to use inference on the entire image at once (disabled) or divide the image (enabled) on smaller chunks, based on your memory constraints.
7272
* **Window overlap**: Define the overlap between windows to reduce border effects;
7373
recommended values are 0.1-0.3 for 3D inference.
7474
* **Keep on CPU**: You can choose to keep the dataset in RAM rather than VRAM to avoid running out of VRAM if you have several images.
7575
* **Device Selection**: You can choose to run inference on either CPU or GPU. A GPU is recommended for faster inference.
7676

77-
* **Anisotropy** :
77+
* **Anisotropy**:
7878

7979
For **anisotropic images** you may set the **resolution of your volume in micron**, to view and save the results without anisotropy.
8080

81-
* **Thresholding** :
81+
* **Thresholding**:
8282

8383
You can perform thresholding to **binarize your labels**.
8484
All values below the **confidence threshold** will be set to 0.
@@ -87,7 +87,7 @@ Interface and functionalities
8787
It is recommended to first run without thresholding. You can then use the napari contrast limits to find a good threshold value,
8888
and run inference later with your chosen threshold.
8989

90-
* **Instance segmentation** :
90+
* **Instance segmentation**:
9191

9292
| You can convert the semantic segmentation into instance labels by using either the `Voronoi-Otsu`_, `Watershed`_ or `Connected Components`_ method, as detailed in :ref:`utils_module_guide`.
9393
| Instance labels will be saved (and shown if applicable) separately from other results.
@@ -98,7 +98,7 @@ Interface and functionalities
9898
.. _Voronoi-Otsu: https://haesleinhuepf.github.io/BioImageAnalysisNotebooks/20_image_segmentation/11_voronoi_otsu_labeling.html
9999

100100

101-
* **Computing objects statistics** :
101+
* **Computing objects statistics**:
102102

103103
You can choose to compute various stats from the labels and save them to a **`.csv`** file for later use.
104104
Statistics include individual object details and general metrics.
@@ -109,7 +109,7 @@ Interface and functionalities
109109
* Sphericity
110110

111111

112-
Global metrics :
112+
Global metrics:
113113

114114
* Image size
115115
* Total image volume (pixels)
@@ -118,7 +118,7 @@ Interface and functionalities
118118
* The number of labeled objects
119119

120120

121-
* **Display options** :
121+
* **Display options**:
122122

123123
When running inference on a folder, you can choose to display the results in napari.
124124
If selected, you may choose the display quantity, and whether to display the original image alongside the results.
@@ -151,7 +151,16 @@ Unsupervised model - WNet3D
151151
| The `WNet3D model` is a fully self-supervised model used to segment images without any labels.
152152
| It functions similarly to the above models, with a few notable differences.
153153
154-
.. _WNet3D model: https://arxiv.org/abs/1711.08506
154+
WNet3D has been tested on:
155+
156+
* **MesoSPIM** data (whole-brain samples of mice imaged by mesoSPIM microscopy) with nuclei staining.
157+
* Other microscopy (i.e., confocal) data with:
158+
* **Sufficient contrast** between objects and background.
159+
* **Low to medium crowding** of objects. If all objects are adjacent to each other, instance segmentation methods provided here may not work well.
160+
161+
Noise and object size are less critical, though objects still have to fit within the field of view of the model.
162+
163+
.. _WNet3D model: https://elifesciences.org/reviewed-preprints/99848
155164

156165
.. note::
157166
Our provided, pre-trained model uses an input size of 64x64x64. As such, window inference is always enabled

docs/source/guides/utils_module_guide.rst

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,21 @@ See `Usage section <https://adaptivemotorcontrollab.github.io/CellSeg3d/welcome.
1111

1212
You may specify the results directory for saving; afterwards you can run each action on a folder or on the currently selected layer.
1313

14+
Default Paths for Saving Results
15+
________________________________
16+
17+
Each utility saves results to a default directory under the user's home directory. The default paths are as follows:
18+
19+
* Artifact Removal: ``~/cellseg3d/artifact_removed``
20+
* Fragmentation: ``~/cellseg3d/fragmented``
21+
* Anisotropy Correction: ``~/cellseg3d/anisotropy``
22+
* Small Object Removal: ``~/cellseg3d/small_removed``
23+
* Semantic Label Conversion: ``~/cellseg3d/semantic_labels``
24+
* Instance Label Conversion: ``~/cellseg3d/instance_labels``
25+
* Thresholding: ``~/cellseg3d/threshold``
26+
* Statistics: ``~/cellseg3d/stats``
27+
* Threshold Grid Search: ``~/cellseg3d/threshold_grid_search``
28+
1429
Available actions
1530
__________________
1631

@@ -89,6 +104,18 @@ Global metrics :
89104
| Clears labels that are larger than a given threshold.
90105
| This is useful for removing artifacts that are larger than the objects of interest.
91106
107+
11. Find the best threshold
108+
-----------------------
109+
| Finds the best threshold for separating objects from the background.
110+
| Requires a prediction from a model and GT labels as input.
111+
112+
.. caution::
113+
If the input prediction is not from the plugin, it will be remapped to the 0-1 range.
114+
115+
| The threshold is found by maximizing the Dice coefficient between the thresolded prediction and the binarized GT labels.
116+
117+
| The value for the best threshold will be displayed, and the prediction will be thresholded and saved with this value.
118+
92119
Source code
93120
___________
94121

docs/welcome.rst

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,14 @@ Welcome to CellSeg3D!
99
Use CellSeg3D to:
1010

1111
* Review labeled cell volumes from whole-brain samples of mice imaged by mesoSPIM microscopy [1]_
12-
* Train and use segmentation models from the MONAI project [2]_ or implement your own custom 3D segmentation models using PyTorch.
12+
* Train and use segmentation models from the MONAI project [2]_
13+
* Train and use our WNet3D unsupervised model
14+
* Or implement your own custom 3D segmentation models using PyTorch!
1315

14-
No labeled data? Try our unsupervised model, based on the `WNet`_ model, to automate your data labelling.
15-
16-
The models provided should be adaptable to other tasks related to detection of 3D objects,
17-
outside of whole-brain light-sheet microscopy.
18-
This applies to the unsupervised model as well, feel free to try to generate labels for your own data!
1916

2017
.. figure:: https://images.squarespace-cdn.com/content/v1/57f6d51c9f74566f55ecf271/0d16a71b-3ff2-477a-9d83-18d96cb1ce28/full_demo.gif?format=500w
2118
:alt: CellSeg3D demo
22-
:width: 500
19+
:width: 800
2320
:align: center
2421

2522
Demo of the plugin
@@ -145,14 +142,14 @@ Other useful napari plugins
145142

146143
Acknowledgments & References
147144
---------------------------------------------
148-
This plugin has been developed by Cyril Achard and Maxime Vidal, supervised by Mackenzie Mathis for the `Mathis Laboratory of Adaptive Motor Control`_.
145+
If you find our code or ideas useful, please cite:
146+
147+
Achard Cyril, Kousi Timokleia, Frey Markus, Vidal Maxime, Paychère Yves, Hofmann Colin, Iqbal Asim, Hausmann Sebastien B, Pagès Stéphane, Mathis Mackenzie Weygandt (2024)
148+
CellSeg3D: self-supervised 3D cell segmentation for microscopy eLife https://doi.org/10.7554/eLife.99848.1
149149

150-
We also greatly thank Timokleia Kousi for her contributions to this project and the `Wyss Center`_ for project funding.
151150

152-
The TRAILMAP models and original weights used here were ported to PyTorch but originate from the `TRAILMAP project on GitHub`_.
153-
We also provide a model that was trained in-house on mesoSPIM nuclei data in collaboration with Dr. Stephane Pages and Timokleia Kousi.
154151

155-
This plugin mainly uses the following libraries and software:
152+
This plugin additionally uses the following libraries and software:
156153

157154
* `napari`_
158155

@@ -162,9 +159,9 @@ This plugin mainly uses the following libraries and software:
162159

163160
* `pyclEsperanto`_ (for the Voronoi Otsu labeling) by Robert Haase
164161

165-
* A new unsupervised 3D model based on the `WNet`_ by Xia and Kulis [3]_
166162

167-
.. _Mathis Laboratory of Adaptive Motor Control: http://www.mackenziemathislab.org/
163+
164+
.. _Mathis Laboratory of Adaptive Intelligence: http://www.mackenziemathislab.org/
168165
.. _Wyss Center: https://wysscenter.ch/
169166
.. _TRAILMAP project on GitHub: https://github.com/AlbertPun/TRAILMAP
170167
.. _napari: https://napari.org/
@@ -178,4 +175,3 @@ This plugin mainly uses the following libraries and software:
178175

179176
.. [1] The mesoSPIM initiative: open-source light-sheet microscopes for imaging cleared tissue, Voigt et al., 2019 ( https://doi.org/10.1038/s41592-019-0554-0 )
180177
.. [2] MONAI Project website ( https://monai.io/ )
181-
.. [3] W-Net: A Deep Model for Fully Unsupervised Image Segmentation, Xia and Kulis, 2018 ( https://arxiv.org/abs/1711.08506 )

napari_cellseg3d/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
"""napari-cellseg3d - napari plugin for cell segmentation."""
2-
__version__ = "0.2.0"
2+
3+
__version__ = "0.2.1"

napari_cellseg3d/code_models/instance_segmentation.py

Lines changed: 23 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
"""Instance segmentation methods for 3D images."""
2+
23
import abc
34
from dataclasses import dataclass
45
from functools import partial
@@ -128,14 +129,14 @@ def record_parameters(self):
128129
"""Records all the parameters of the instance segmentation method from the current values of the widgets."""
129130
if len(self.sliders) > 0:
130131
for slider in self.sliders:
131-
self.recorded_parameters[
132-
slider.label.text()
133-
] = slider.slider_value
132+
self.recorded_parameters[slider.label.text()] = (
133+
slider.slider_value
134+
)
134135
if len(self.counters) > 0:
135136
for counter in self.counters:
136-
self.recorded_parameters[
137-
counter.label.text()
138-
] = counter.value()
137+
self.recorded_parameters[counter.label.text()] = (
138+
counter.value()
139+
)
139140

140141
def run_method_from_params(self, image):
141142
"""Runs the method on the image with the RECORDED parameters set in the widget.
@@ -327,10 +328,8 @@ def binary_connected(
327328
)
328329
semantic = np.squeeze(volume)
329330
foreground = np.where(semantic > thres, volume, 0) # int(255 * thres)
330-
segm = label(foreground)
331-
segm = remove_small_objects(segm, thres_small)
332-
333-
return segm
331+
seg = label(foreground)
332+
return remove_small_objects(seg, thres_small)
334333

335334

336335
def binary_watershed(
@@ -419,15 +418,10 @@ def clear_small_objects(image, threshold, is_file_path=False):
419418
if is_file_path:
420419
image = imread(image)
421420

422-
# print(threshold)
423-
424421
labeled = label(image)
425422

426423
result = remove_small_objects(labeled, threshold)
427424

428-
# print(np.sum(labeled))
429-
# print(np.sum(result))
430-
431425
if np.sum(labeled) == np.sum(result):
432426
print("Warning : no objects were removed")
433427

@@ -551,9 +545,9 @@ def __init__(self, widget_parent=None):
551545
)
552546

553547
self.sliders[0].label.setText("Foreground probability threshold")
554-
self.sliders[
555-
0
556-
].tooltips = "Probability threshold for foreground object"
548+
self.sliders[0].tooltips = (
549+
"Probability threshold for foreground object"
550+
)
557551
self.sliders[0].setValue(500)
558552

559553
self.sliders[1].label.setText("Seed probability threshold")
@@ -652,9 +646,9 @@ def __init__(self, widget_parent=None):
652646
)
653647

654648
self.sliders[0].label.setText("Foreground probability threshold")
655-
self.sliders[
656-
0
657-
].tooltips = "Probability threshold for foreground object"
649+
self.sliders[0].tooltips = (
650+
"Probability threshold for foreground object"
651+
)
658652
self.sliders[0].setValue(800)
659653

660654
self.counters[0].label.setText("Small objects removal")
@@ -715,18 +709,18 @@ def __init__(self, widget_parent=None):
715709
widget_parent=widget_parent,
716710
)
717711
self.counters[0].label.setText("Spot sigma") # closeness
718-
self.counters[
719-
0
720-
].tooltips = "Determines how close detected objects can be"
712+
self.counters[0].tooltips = (
713+
"Determines how close detected objects can be"
714+
)
721715
self.counters[0].setMaximum(100)
722-
self.counters[0].setValue(2)
716+
self.counters[0].setValue(0.65)
723717

724718
self.counters[1].label.setText("Outline sigma") # smoothness
725-
self.counters[
726-
1
727-
].tooltips = "Determines the smoothness of the segmentation"
719+
self.counters[1].tooltips = (
720+
"Determines the smoothness of the segmentation"
721+
)
728722
self.counters[1].setMaximum(100)
729-
self.counters[1].setValue(2)
723+
self.counters[1].setValue(0.65)
730724

731725
self.counters[2].label.setText("Small object removal")
732726
self.counters[2].tooltips = (

napari_cellseg3d/code_models/models/TEMPLATE_model.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
33
Please note that custom model implementations are not fully supported out of the box yet, but might be in the future.
44
"""
5+
56
from abc import ABC, abstractmethod
67

78

@@ -11,6 +12,7 @@ class ModelTemplate_(ABC):
1112
weights_file = (
1213
"model_template.pth" # specify the file name of the weights file only
1314
)
15+
default_threshold = 0.5 # specify the default threshold for the model
1416

1517
@abstractmethod
1618
def __init__(

napari_cellseg3d/code_models/models/model_SegResNet.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
"""SegResNet wrapper for napari_cellseg3d."""
2+
23
from monai.networks.nets import SegResNetVAE
34

45

56
class SegResNet_(SegResNetVAE):
67
"""SegResNet_ wrapper for napari_cellseg3d."""
78

89
weights_file = "SegResNet_latest.pth"
10+
default_threshold = 0.3
911

1012
def __init__(
1113
self, input_img_size, out_channels=1, dropout_prob=0.3, **kwargs

napari_cellseg3d/code_models/models/model_SwinUNetR.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
"""SwinUNetR wrapper for napari_cellseg3d."""
2+
23
from monai.networks.nets import SwinUNETR
34

45
from napari_cellseg3d.utils import LOGGER
@@ -10,6 +11,7 @@ class SwinUNETR_(SwinUNETR):
1011
"""SwinUNETR wrapper for napari_cellseg3d."""
1112

1213
weights_file = "SwinUNetR_latest.pth"
14+
default_threshold = 0.4
1315

1416
def __init__(
1517
self,

napari_cellseg3d/code_models/models/model_TRAILMAP_MS.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
"""TRAILMAP model, reimplemented in PyTorch."""
2+
23
from napari_cellseg3d.code_models.models.unet.model import UNet3D
34
from napari_cellseg3d.utils import LOGGER as logger
45

@@ -7,6 +8,7 @@ class TRAILMAP_MS_(UNet3D):
78
"""TRAILMAP_MS wrapper for napari_cellseg3d."""
89

910
weights_file = "TRAILMAP_MS_best_metric.pth"
11+
default_threshold = 0.15
1012

1113
# original model from Liqun Luo lab, transferred to pytorch and trained on mesoSPIM-acquired data (mostly TPH2 as of July 2022)
1214

0 commit comments

Comments
 (0)