Skip to content

Commit ae4ff74

Browse files
committed
changed csv format for easier access + updated plots + moved stats to worker + tooltips + trying to fix readme
1 parent d253a57 commit ae4ff74

File tree

13 files changed

+356
-331
lines changed

13 files changed

+356
-331
lines changed

.github/workflows/test_and_deploy.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
# strategy:
2424
# matrix:
2525
# platform: [windows-latest, macos-latest, ubuntu-latest]
26-
# python-version: [3.9]
26+
# python-version: [3.8, 3.9]
2727
#
2828
# steps:
2929
# - uses: actions/checkout@v2

README.md

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
# napari-cellseg3d
22

3-
[![License](https://img.shields.io/pypi/l/napari-cellseg3d.svg?color=green)](https://github.com/C_Achard/napari-cellseg3d/raw/main/LICENSE)
4-
[![PyPI](https://img.shields.io/pypi/v/napari-cellseg3d.svg?color=green)](https://pypi.org/project/napari-cellseg3d)
3+
[![License](https://img.shields.io/pypi/l/napari-cellseg3d.svg?color=green)](https://github.com/C_Achard/napari-cellseg-annotator/raw/main/LICENSE)
4+
[![PyPI](https://img.shields.io/pypi/v/napari-cellseg3d.svg?color=green)](https://pypi.org/project/napari-cellseg-annotator)
55
[![Python Version](https://img.shields.io/pypi/pyversions/napari-cellseg3d.svg?color=green)](https://python.org)
6-
[![tests](https://github.com/C_Achard/napari-cellseg3d/workflows/tests/badge.svg)](https://github.com/C_Achard/napari-cellseg3d/actions)
7-
[![codecov](https://codecov.io/gh/C_Achard/napari-cellseg3d/branch/main/graph/badge.svg)](https://codecov.io/gh/C_Achard/napari-cellseg3d)
8-
[![napari hub](https://img.shields.io/endpoint?url=https://api.napari-hub.org/shields/napari-cellseg3d)](https://napari-hub.org/plugins/napari-cellseg3d)
6+
[![tests](https://github.com/C_Achard/napari-cellseg3d/workflows/tests/badge.svg)](https://github.com/C_Achard/napari-cellseg-annotator/actions)
7+
[![codecov](https://codecov.io/gh/C_Achard/napari-cellseg3d/branch/main/graph/badge.svg)](https://codecov.io/gh/C_Achard/napari-cellseg-annotator)
8+
[![napari hub](https://img.shields.io/endpoint?url=https://api.napari-hub.org/shields/napari-cellseg3d)](https://napari-hub.org/plugins/cellseg-annotator-test)
99

10-
plugin for cell segmentation
10+
napari plugin providing cell segmentation tools : training, inference, review...
1111

1212
----------------------------------
1313

@@ -23,8 +23,11 @@ https://napari.org/plugins/stable/index.html
2323

2424
## Requirements
2525

26-
Requires manual installation of pytorch and MONAI.
27-
For Pytorch, please see [PyTorch]'s website for installation instructions.
26+
**Python >= 3.8 required**
27+
28+
Requires manual installation of **pytorch** and **MONAI**.
29+
30+
For Pytorch, please see [PyTorch's website for installation instructions].
2831
A CUDA-capable GPU is not needed but very strongly recommended, especially for training.
2932

3033
If you get errors from MONAI regarding missing readers, please see [MONAI's optional dependencies] page for instructions on getting the readers required by your images.
@@ -44,7 +47,7 @@ pip install -e .
4447

4548
## Documentation
4649

47-
You can generate docs by running ``make html`` in the docs folder
50+
You can generate docs by running ``make html`` in the *docs* folder
4851

4952
## Usage
5053

@@ -97,5 +100,5 @@ If you encounter any problems, please [file an issue] along with a detailed desc
97100
[pip]: https://pypi.org/project/pip/
98101
[PyPI]: https://pypi.org/
99102

100-
[PyTorch]: https://pytorch.org/get-started/locally/
103+
[PyTorch's website for installation instructions]: https://pytorch.org/get-started/locally/
101104
[MONAI's optional dependencies]: https://docs.monai.io/en/stable/installation.html#installing-the-recommended-dependencies

docs/res/guides/inference_module_guide.rst

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,7 @@ Interface and functionalities
4040

4141
| You can then choose one of the provided **models** above, which will be used for inference.
4242
| You may also choose to **load custom weights** rather than the pre-trained ones, simply ensure they are **compatible** (e.g. produced from the training module for the same model)
43-
44-
.. note::
45-
Currently the SegResNet model requires you to provide the size of the images the model was trained with due to the VAE module.
46-
Provided weights use a size of 128, please leave it as is if you're not using custom weights.
43+
| If you choose to use a SegResNet with custom weights, you will have to provide the size of images it was trained on to ensure compatibility. (See note below)
4744
4845
* **Inference parameters** :
4946

@@ -106,6 +103,10 @@ Once it has finished, results will be saved then displayed in napari; each outpu
106103
On the left side, a progress bar and a log will keep you informed on the process.
107104

108105

106+
.. note::
107+
Currently the SegResNet model requires you to provide the size of the images the model was trained with due to the VAE module.
108+
Provided weights use a size of 128, please leave it as is if you're not using custom weights.
109+
109110

110111
.. note::
111112
| The files will be saved using the following format :

napari_cellseg3d/model_instance_seg.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
import numpy as np
55
from skimage.measure import label
6+
67
# from skimage.measure import marching_cubes
78
# from skimage.measure import mesh_surface_area
89
from skimage.measure import regionprops
@@ -13,6 +14,7 @@
1314

1415
from napari_cellseg3d.utils import fill_list_in_between
1516
from napari_cellseg3d.utils import sphericity_axis
17+
1618
# from napari_cellseg3d.utils import sphericity_volume_area
1719

1820

@@ -189,7 +191,7 @@ def volume_stats(volume_image):
189191
190192
Returns:
191193
dict: Statistics described above
192-
"""
194+
"""
193195

194196
properties = regionprops(volume_image)
195197
number_objects = np.amax(volume_image)
@@ -218,7 +220,9 @@ def fill(lst, n=len(properties) - 1):
218220

219221
return {
220222
"Volume": volume,
221-
"Centroid": [region.centroid for region in properties],
223+
"Centroid x": [region.centroid[0] for region in properties],
224+
"Centroid y": [region.centroid[1] for region in properties],
225+
"Centroid z": [region.centroid[2] for region in properties],
222226
# "Sphericity (volume/area)": sphericity_va,
223227
"Sphericity (axes)": sphericity_ax,
224228
"Image size": fill([volume_image.shape]),

napari_cellseg3d/model_workers.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
# local
4545
from napari_cellseg3d.model_instance_seg import binary_connected
4646
from napari_cellseg3d.model_instance_seg import binary_watershed
47+
from napari_cellseg3d.model_instance_seg import volume_stats
4748

4849
"""
4950
Writing something to log messages from outside the main thread is rather problematic (plenty of silent crashes...)
@@ -92,6 +93,7 @@ def __init__(
9293
use_window,
9394
window_infer_size,
9495
keep_on_cpu,
96+
stats_csv,
9597
):
9698
"""Initializes a worker for inference with the arguments needed by the :py:func:`~inference` function.
9799
@@ -118,6 +120,8 @@ def __init__(
118120
119121
* keep_on_cpu: keep images on CPU or no
120122
123+
* stats_csv: compute stats on cells and save them to a csv file
124+
121125
Note: See :py:func:`~self.inference`
122126
"""
123127

@@ -137,6 +141,7 @@ def __init__(
137141
self.use_window = use_window
138142
self.window_infer_size = window_infer_size
139143
self.keep_on_cpu = keep_on_cpu
144+
self.stats_to_csv = stats_csv
140145

141146
"""These attributes are all arguments of :py:func:~inference, please see that for reference"""
142147

@@ -215,6 +220,8 @@ def inference(self):
215220
216221
* keep_on_cpu: keep images on CPU or no
217222
223+
* stats_csv: compute stats on cells and save them to a csv file
224+
218225
Yields:
219226
dict: contains :
220227
* "image_id" : index of the returned image
@@ -447,6 +454,14 @@ def method(image):
447454
f"Instance segmentation results for image n°{image_id} have been saved as:"
448455
)
449456
self.log(os.path.split(instance_filepath)[1])
457+
458+
if self.stats_to_csv:
459+
data_dict = volume_stats(
460+
instance_labels
461+
) # TODO test with area mesh function
462+
else:
463+
data_dict = None
464+
450465
else:
451466
instance_labels = None
452467

@@ -457,6 +472,7 @@ def method(image):
457472
"image_id": i + 1,
458473
"original": original,
459474
"instance_labels": instance_labels,
475+
"object stats": data_dict,
460476
"result": out,
461477
"model_name": self.model_dict["name"],
462478
}

napari_cellseg3d/plugin_base.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,9 @@ def __init__(self, viewer: "napari.viewer.Viewer", parent=None):
209209

210210
def make_close_button(self):
211211
btn = ui.make_button("Close", self.remove_from_viewer)
212+
btn.setToolTip(
213+
"Close the window and all docked widgets. Make sure to save your work !"
214+
)
212215
return btn
213216

214217
def make_prev_button(self):

napari_cellseg3d/plugin_model_inference.py

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
from napari_cellseg3d import interface as ui
1313
from napari_cellseg3d import utils
1414
from napari_cellseg3d.model_framework import ModelFramework
15-
from napari_cellseg3d.model_instance_seg import volume_stats
1615
from napari_cellseg3d.model_workers import InferenceWorker
1716

1817

@@ -587,6 +586,7 @@ def start(self): # TODO update
587586
use_window=self.use_window_inference,
588587
window_infer_size=self.window_inference_size,
589588
keep_on_cpu=self.keep_on_cpu,
589+
stats_csv=self.stats_to_csv,
590590
)
591591

592592
yield_connect_show_res = lambda data: self.on_yield(
@@ -703,21 +703,12 @@ def on_yield(data, widget):
703703

704704
instance_layer = viewer.add_labels(labels, name=name)
705705

706-
if widget.stats_to_csv: # TODO move to worker
706+
data_dict = data["object stats"]
707+
if (
708+
widget.stats_to_csv and data_dict is not None
709+
): # TODO move to worker
707710

708-
cell_data = volume_stats(
709-
labels
710-
) # TODO test with area mesh function
711-
# count = np.tile("", len(cell_data["Volume"])-1)
712-
# cell_data["Cell count"] = np.insert(count, 0, number_cells)
713-
# cell_data["Total cell volume"] = np.insert(
714-
# count, 0, tot_cell_volume
715-
# )
716-
# cell_data["Cell volume ratio"] = np.insert(
717-
# count, 0, tot_cell_volume / len(labels.flatten())
718-
# )
719-
720-
numeric_data = pd.DataFrame(cell_data)
711+
numeric_data = pd.DataFrame(data_dict)
721712

722713
csv_name = f"/{method}_seg_results_{image_id}_{utils.get_date_time()}.csv"
723714
numeric_data.to_csv(

napari_cellseg3d/plugin_model_training.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,54 @@ def __init__(
319319
self.btn_model_path.setVisible(False)
320320
self.lbl_model_path.setVisible(False)
321321

322+
############################
323+
############################
324+
# tooltips
325+
self.zip_choice.setToolTip(
326+
"Checking this will save a copy of the results as a zip folder"
327+
)
328+
self.validation_percent_choice.setToolTip(
329+
"Choose the proportion of images to retain for training.\nThe remaining images will be used for validation"
330+
)
331+
self.epoch_choice.setToolTip(
332+
"The number of epochs to train for.\nThe more you train, the better the model will fit the training data"
333+
)
334+
self.loss_choice.setToolTip(
335+
"The loss function to use for training.\nSee the list in the inference guide for more info"
336+
)
337+
self.sample_choice.setToolTip(
338+
"The number of samples to extract per image"
339+
)
340+
self.batch_choice.setToolTip(
341+
"The batch size to use for training.\n A larger value will feed more images per iteration to the model,\n"
342+
" which is faster and possibly improves performance, but uses more memory"
343+
)
344+
self.val_interval_choice.setToolTip(
345+
"The number of epochs to perform before validating data.\n "
346+
"The lower the value, the more often the score of the model will be computed and the more often the weights will be saved."
347+
)
348+
self.learning_rate_choice.setToolTip(
349+
"The learning rate to use in the optimizer. \nUse a lower value if you're using pre-trained weights"
350+
)
351+
self.augment_choice.setToolTip(
352+
"Check this to enable data augmentation, which will randomly deform, flip and shift the intensity in images"
353+
" to provide a more general dataset. \nUse this if you're extracting more than 10 samples per image"
354+
)
355+
[
356+
w.setToolTip("Size of the sample to extract")
357+
for w in self.patch_size_widgets
358+
]
359+
self.patch_choice.setToolTip(
360+
"Check this to automatically crop your images in smaller, cubic images for training."
361+
"\nShould be used if you have a small dataset (and large images)"
362+
)
363+
self.use_deterministic_choice.setToolTip("Enable deterministic training for reproducibility."
364+
"Using the same seed with all other parameters being similar should yield the exact same results between two runs.")
365+
self.use_transfer_choice.setToolTip("Use this you want to initialize the model with pre-trained weights or use your own weights.")
366+
self.box_seed.setToolTip("Seed to use for RNG")
367+
############################
368+
############################
369+
322370
self.build()
323371

324372
def toggle_patch_dims(self):

notebooks/csv_cell_plot.ipynb

Lines changed: 11 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
"metadata": {},
3030
"outputs": [],
3131
"source": [
32-
"dat1 = pd.read_csv(\"data_plot.csv\", index_col=False)"
32+
"dat1 = pd.read_csv(\"plots_data.csv\", index_col=False)"
3333
]
3434
},
3535
{
@@ -53,18 +53,9 @@
5353
"\n",
5454
" data = pd.read_csv(data_path, index_col=False)\n",
5555
"\n",
56-
" x = [\n",
57-
" float(data[\"Centroid\"][i][1:-2].split(\",\")[0])\n",
58-
" for i in range(len(data[\"Centroid\"]))\n",
59-
" ]\n",
60-
" y = [\n",
61-
" float(data[\"Centroid\"][i][1:-2].split(\",\")[1])\n",
62-
" for i in range(len(data[\"Centroid\"]))\n",
63-
" ]\n",
64-
" z = [\n",
65-
" float(data[\"Centroid\"][i][1:-2].split(\",\")[2])\n",
66-
" for i in range(len(data[\"Centroid\"]))\n",
67-
" ]\n",
56+
" x = data[\"Centroid x\"]\n",
57+
" y = data[\"Centroid y\"]\n",
58+
" z = data[\"Centroid z\"]\n",
6859
"\n",
6960
" x = np.floor(x)\n",
7061
" y = np.floor(y)\n",
@@ -133,7 +124,7 @@
133124
"metadata": {},
134125
"outputs": [],
135126
"source": [
136-
"plot_data(\"data_plot.csv\")"
127+
"plot_data(\"plots_data.csv\")"
137128
]
138129
},
139130
{
@@ -143,7 +134,7 @@
143134
"metadata": {},
144135
"outputs": [],
145136
"source": [
146-
"dat2 = pd.read_csv(\"data_plot_2.csv\", index_col=False)"
137+
"dat2 = pd.read_csv(\"plots_data2.csv\", index_col=False)"
147138
]
148139
},
149140
{
@@ -153,7 +144,7 @@
153144
"metadata": {},
154145
"outputs": [],
155146
"source": [
156-
"plot_data(\"data_plot_2.csv\", z_inv=True, x_inv=True)"
147+
"plot_data(\"plots_data2.csv\", z_inv=True, x_inv=True)"
157148
]
158149
},
159150
{
@@ -189,18 +180,9 @@
189180
"\n",
190181
" init_notebook_mode() # initiate notebook for offline plot\n",
191182
"\n",
192-
" x = [\n",
193-
" float(data[\"Centroid\"][i][1:-2].split(\",\")[0])\n",
194-
" for i in range(len(data[\"Centroid\"]))\n",
195-
" ]\n",
196-
" y = [\n",
197-
" float(data[\"Centroid\"][i][1:-2].split(\",\")[1])\n",
198-
" for i in range(len(data[\"Centroid\"]))\n",
199-
" ]\n",
200-
" z = [\n",
201-
" float(data[\"Centroid\"][i][1:-2].split(\",\")[2])\n",
202-
" for i in range(len(data[\"Centroid\"]))\n",
203-
" ]\n",
183+
" x = data[\"Centroid x\"]\n",
184+
" y = data[\"Centroid y\"]\n",
185+
" z = data[\"Centroid z\"]\n",
204186
"\n",
205187
" fig = go.Figure(\n",
206188
" data=go.Scatter3d(\n",
@@ -214,7 +196,7 @@
214196
" sizemin=20,\n",
215197
" size=data[\"Volume\"],\n",
216198
" color=data[\"Sphericity (axes)\"],\n",
217-
" colorscale=\"Viridis\",\n",
199+
" colorscale=\"Turbo_r\",\n",
218200
" colorbar_title=\"Sphericity\",\n",
219201
" line_color=\"rgb(140, 140, 170)\",\n",
220202
" ),\n",

0 commit comments

Comments
 (0)