cellfinder 1.4.1__py3-none-any.whl → 1.9.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. cellfinder/cli_migration_warning.py +3 -1
  2. cellfinder/core/classify/classify.py +51 -5
  3. cellfinder/core/classify/tools.py +13 -3
  4. cellfinder/core/detect/detect.py +94 -59
  5. cellfinder/core/detect/filters/plane/plane_filter.py +107 -10
  6. cellfinder/core/detect/filters/setup_filters.py +51 -12
  7. cellfinder/core/detect/filters/volume/ball_filter.py +5 -5
  8. cellfinder/core/detect/filters/volume/structure_detection.py +5 -0
  9. cellfinder/core/detect/filters/volume/structure_splitting.py +3 -2
  10. cellfinder/core/detect/filters/volume/volume_filter.py +1 -1
  11. cellfinder/core/download/download.py +2 -1
  12. cellfinder/core/main.py +162 -30
  13. cellfinder/core/tools/threading.py +4 -3
  14. cellfinder/core/tools/tools.py +1 -1
  15. cellfinder/core/train/{train_yml.py → train_yaml.py} +6 -15
  16. cellfinder/napari/curation.py +72 -21
  17. cellfinder/napari/detect/detect.py +87 -28
  18. cellfinder/napari/detect/detect_containers.py +41 -9
  19. cellfinder/napari/detect/thread_worker.py +26 -16
  20. cellfinder/napari/input_container.py +14 -4
  21. cellfinder/napari/train/train.py +5 -9
  22. cellfinder/napari/train/train_containers.py +2 -4
  23. cellfinder/napari/utils.py +6 -1
  24. {cellfinder-1.4.1.dist-info → cellfinder-1.9.0.dist-info}/METADATA +16 -12
  25. {cellfinder-1.4.1.dist-info → cellfinder-1.9.0.dist-info}/RECORD +29 -29
  26. {cellfinder-1.4.1.dist-info → cellfinder-1.9.0.dist-info}/WHEEL +1 -1
  27. {cellfinder-1.4.1.dist-info → cellfinder-1.9.0.dist-info}/entry_points.txt +1 -1
  28. {cellfinder-1.4.1.dist-info → cellfinder-1.9.0.dist-info/licenses}/LICENSE +0 -0
  29. {cellfinder-1.4.1.dist-info → cellfinder-1.9.0.dist-info}/top_level.txt +0 -0
@@ -148,7 +148,7 @@ def restore_options_defaults(widget: FunctionGui) -> None:
148
148
 
149
149
 
150
150
  def get_results_callback(
151
- skip_classification: bool, viewer: napari.Viewer
151
+ skip_classification: bool, viewer: napari.Viewer, scale
152
152
  ) -> Callable:
153
153
  """
154
154
  Returns the callback that is connected to output of the pipeline.
@@ -162,6 +162,7 @@ def get_results_callback(
162
162
  viewer=viewer,
163
163
  name="Cell candidates",
164
164
  cell_type=Cell.UNKNOWN,
165
+ scale=scale,
165
166
  )
166
167
 
167
168
  else:
@@ -172,6 +173,7 @@ def get_results_callback(
172
173
  viewer=viewer,
173
174
  unknown_name="Rejected",
174
175
  cell_name="Detected",
176
+ scale=scale,
175
177
  )
176
178
 
177
179
  return done_func
@@ -244,23 +246,28 @@ def detect_widget() -> FunctionGui:
244
246
  detection_options,
245
247
  skip_detection: bool,
246
248
  soma_diameter: float,
249
+ log_sigma_size: float,
250
+ n_sds_above_mean_thresh: float,
251
+ n_sds_above_mean_tiled_thresh: float,
252
+ tiled_thresh_tile_size: float,
247
253
  ball_xy_size: float,
248
254
  ball_z_size: float,
249
255
  ball_overlap_fraction: float,
250
- log_sigma_size: float,
251
- n_sds_above_mean_thresh: int,
256
+ detection_batch_size: int,
252
257
  soma_spread_factor: float,
253
- max_cluster_size: int,
258
+ max_cluster_size: float,
254
259
  classification_options,
255
260
  skip_classification: bool,
256
261
  use_pre_trained_weights: bool,
257
262
  trained_model: Optional[Path],
258
- batch_size: int,
263
+ classification_batch_size: int,
259
264
  misc_options,
260
265
  start_plane: int,
261
266
  end_plane: int,
262
267
  n_free_cpus: int,
263
268
  analyse_local: bool,
269
+ use_gpu: bool,
270
+ pin_memory: bool,
264
271
  debug: bool,
265
272
  reset_button,
266
273
  ) -> None:
@@ -270,43 +277,74 @@ def detect_widget() -> FunctionGui:
270
277
  Parameters
271
278
  ----------
272
279
  voxel_size_z : float
273
- Size of your voxels in the axial dimension
280
+ Size of your voxels in the axial dimension (microns)
274
281
  voxel_size_y : float
275
- Size of your voxels in the y direction (top to bottom)
282
+ Size of your voxels in the y direction (top to bottom) (microns)
276
283
  voxel_size_x : float
277
- Size of your voxels in the x direction (left to right)
284
+ Size of your voxels in the x direction (left to right) (microns)
278
285
  skip_detection : bool
279
286
  If selected, the detection step is skipped and instead we get the
280
287
  detected cells from the cell layer below (from a previous
281
288
  detection run or import)
282
289
  soma_diameter : float
283
- The expected in-plane soma diameter (microns)
290
+ The expected in-plane (xy) soma diameter (microns)
291
+ log_sigma_size : float
292
+ Gaussian filter width (as a fraction of soma diameter) used during
293
+ 2d in-plane Laplacian of Gaussian filtering
294
+ n_sds_above_mean_thresh : float
295
+ Per-plane intensity threshold (the number of standard deviations
296
+ above the mean) of the filtered 2d planes used to mark pixels as
297
+ foreground or background
298
+ n_sds_above_mean_tiled_thresh : float
299
+ Per-plane, per-tile intensity threshold (the number of standard
300
+ deviations above the mean) for the filtered 2d planes used to mark
301
+ pixels as foreground or background. When used, (tile size is not
302
+ zero) a pixel is marked as foreground if its intensity is above
303
+ both the per-plane and per-tile threshold. I.e. it's above the set
304
+ number of standard deviations of the per-plane average and of the
305
+ per-plane per-tile average for the tile that contains it.
306
+ tiled_thresh_tile_size : float
307
+ The tile size used to tile the x, y plane to calculate the local
308
+ average intensity for the tiled threshold. The value is multiplied
309
+ by soma diameter (i.e. 1 means one soma diameter). If zero, the
310
+ tiled threshold is disabled and only the per-plane threshold is
311
+ used. Tiling is done with 50% overlap when striding.
284
312
  ball_xy_size : float
285
- Elliptical morphological in-plane filter size (microns)
313
+ 3d filter's in-plane (xy) filter ball size (microns)
286
314
  ball_z_size : float
287
- Elliptical morphological axial filter size (microns)
315
+ 3d filter's axial (z) filter ball size (microns)
288
316
  ball_overlap_fraction : float
289
- Fraction of the morphological filter needed to be filled
290
- to retain a voxel
291
- log_sigma_size : float
292
- Laplacian of Gaussian filter width (as a fraction of soma diameter)
293
- n_sds_above_mean_thresh : int
294
- Cell intensity threshold (as a multiple of noise above the mean)
317
+ 3d filter's fraction of the ball filter needed to be filled by
318
+ foreground voxels, centered on a voxel, to retain the voxel
319
+ detection_batch_size: int
320
+ The number of planes of the original data volume to process at
321
+ once. The GPU/CPU memory must be able to contain this many planes
322
+ for all the filters. For performance-critical applications, tune
323
+ to maximize memory usage without
324
+ running out. Check your GPU/CPU memory to verify it's not full
295
325
  soma_spread_factor : float
296
- Cell spread factor (for splitting up cell clusters)
297
- max_cluster_size : int
298
- Largest putative cell cluster (in cubic um) where splitting
299
- should be attempted
300
- use_pre_trained_weights : bool
301
- Select to use pre-trained model weights
302
- batch_size : int
303
- How many points to classify at one time
326
+ Cell spread factor for determining the largest cell volume before
327
+ splitting up cell clusters. Structures with spherical volume of
328
+ diameter `soma_spread_factor * soma_diameter` or less will not be
329
+ split
330
+ max_cluster_size : float
331
+ Largest detected cell cluster (in cubic um) where splitting
332
+ should be attempted. Clusters above this size will be labeled
333
+ as artifacts
304
334
  skip_classification : bool
305
335
  If selected, the classification step is skipped and all cells from
306
336
  the detection stage are added
337
+ use_pre_trained_weights : bool
338
+ Select to use pre-trained model weights
307
339
  trained_model : Optional[Path]
308
340
  Trained model file path (home directory (default) -> pretrained
309
341
  weights)
342
+ classification_batch_size : int
343
+ How many potential cells to classify at one time. The GPU/CPU
344
+ memory must be able to contain at once this many data cubes for
345
+ the models. For performance-critical applications, tune to
346
+ maximize memory usage without running
347
+ out. Check your GPU/CPU memory to verify it's not full
310
348
  start_plane : int
311
349
  First plane to process (to process a subset of the data)
312
350
  end_plane : int
@@ -315,6 +353,14 @@ def detect_widget() -> FunctionGui:
315
353
  How many CPU cores to leave free
316
354
  analyse_local : bool
317
355
  Only analyse planes around the current position
356
+ use_gpu : bool
357
+ If True, use GPU for processing (if available); otherwise, use CPU.
358
+ pin_memory: bool
359
+ Pins data to be sent to the GPU to the CPU memory. This allows
360
+ faster GPU data speeds, but can only be used if the data used by
361
+ the GPU can stay in the CPU RAM while the GPU uses it. I.e. there's
362
+ enough RAM. Otherwise, if there's a risk of the RAM being paged, it
363
+ shouldn't be used. Defaults to False.
318
364
  debug : bool
319
365
  Increase logging
320
366
  reset_button :
@@ -368,8 +414,11 @@ def detect_widget() -> FunctionGui:
368
414
  ball_overlap_fraction,
369
415
  log_sigma_size,
370
416
  n_sds_above_mean_thresh,
417
+ n_sds_above_mean_tiled_thresh,
418
+ tiled_thresh_tile_size,
371
419
  soma_spread_factor,
372
420
  max_cluster_size,
421
+ detection_batch_size,
373
422
  )
374
423
 
375
424
  if use_pre_trained_weights:
@@ -378,7 +427,7 @@ def detect_widget() -> FunctionGui:
378
427
  skip_classification,
379
428
  use_pre_trained_weights,
380
429
  trained_model,
381
- batch_size,
430
+ classification_batch_size,
382
431
  )
383
432
 
384
433
  if analyse_local:
@@ -389,7 +438,13 @@ def detect_widget() -> FunctionGui:
389
438
  end_plane = len(signal_image.data)
390
439
 
391
440
  misc_inputs = MiscInputs(
392
- start_plane, end_plane, n_free_cpus, analyse_local, debug
441
+ start_plane,
442
+ end_plane,
443
+ n_free_cpus,
444
+ analyse_local,
445
+ use_gpu,
446
+ pin_memory,
447
+ debug,
393
448
  )
394
449
 
395
450
  worker = Worker(
@@ -400,7 +455,11 @@ def detect_widget() -> FunctionGui:
400
455
  )
401
456
 
402
457
  worker.returned.connect(
403
- get_results_callback(skip_classification, options["viewer"])
458
+ get_results_callback(
459
+ skip_classification,
460
+ options["viewer"],
461
+ options["signal_image"].scale,
462
+ )
404
463
  )
405
464
  # Make sure if the worker emits an error, it is propagated to this
406
465
  # thread
@@ -1,8 +1,9 @@
1
- from dataclasses import dataclass
1
+ from dataclasses import dataclass, field
2
2
  from pathlib import Path
3
3
  from typing import List, Optional
4
4
 
5
5
  import numpy
6
+ import torch
6
7
  from brainglobe_utils.cells.cells import Cell
7
8
 
8
9
  from cellfinder.napari.input_container import InputContainer
@@ -30,7 +31,7 @@ class DataInputs(InputContainer):
30
31
  self.voxel_size_x,
31
32
  )
32
33
  # del operator doesn't affect self, because asdict creates a copy of
33
- # fields.
34
+ # the dict.
34
35
  del data_input_dict["voxel_size_z"]
35
36
  del data_input_dict["voxel_size_y"]
36
37
  del data_input_dict["voxel_size_x"]
@@ -67,9 +68,12 @@ class DetectionInputs(InputContainer):
67
68
  ball_z_size: float = 15
68
69
  ball_overlap_fraction: float = 0.6
69
70
  log_sigma_size: float = 0.2
70
- n_sds_above_mean_thresh: int = 10
71
+ n_sds_above_mean_thresh: float = 10
72
+ n_sds_above_mean_tiled_thresh: float = 10
73
+ tiled_thresh_tile_size: float = 0
71
74
  soma_spread_factor: float = 1.4
72
- max_cluster_size: int = 100000
75
+ max_cluster_size: float = 100000
76
+ detection_batch_size: int = 1
73
77
 
74
78
  def as_core_arguments(self) -> dict:
75
79
  return super().as_core_arguments()
@@ -93,17 +97,27 @@ class DetectionInputs(InputContainer):
93
97
  "log_sigma_size", custom_label="Filter width"
94
98
  ),
95
99
  n_sds_above_mean_thresh=cls._custom_widget(
96
- "n_sds_above_mean_thresh", custom_label="Threshold"
100
+ "n_sds_above_mean_thresh", custom_label="Plane threshold"
101
+ ),
102
+ n_sds_above_mean_tiled_thresh=cls._custom_widget(
103
+ "n_sds_above_mean_tiled_thresh", custom_label="Tiled threshold"
104
+ ),
105
+ tiled_thresh_tile_size=cls._custom_widget(
106
+ "tiled_thresh_tile_size",
107
+ custom_label="Thresholding tile size",
97
108
  ),
98
109
  soma_spread_factor=cls._custom_widget(
99
- "soma_spread_factor", custom_label="Cell spread"
110
+ "soma_spread_factor", custom_label="Split cell spread"
100
111
  ),
101
112
  max_cluster_size=cls._custom_widget(
102
113
  "max_cluster_size",
103
- custom_label="Max cluster",
114
+ custom_label="Split max cluster",
104
115
  min=0,
105
116
  max=10000000,
106
117
  ),
118
+ detection_batch_size=cls._custom_widget(
119
+ "detection_batch_size", custom_label="Batch size (detection)"
120
+ ),
107
121
  )
108
122
 
109
123
 
@@ -114,7 +128,7 @@ class ClassificationInputs(InputContainer):
114
128
  skip_classification: bool = False
115
129
  use_pre_trained_weights: bool = True
116
130
  trained_model: Optional[Path] = Path.home()
117
- batch_size: int = 64
131
+ classification_batch_size: int = 64
118
132
 
119
133
  def as_core_arguments(self) -> dict:
120
134
  args = super().as_core_arguments()
@@ -132,7 +146,10 @@ class ClassificationInputs(InputContainer):
132
146
  skip_classification=dict(
133
147
  value=cls.defaults()["skip_classification"]
134
148
  ),
135
- batch_size=dict(value=cls.defaults()["batch_size"]),
149
+ classification_batch_size=dict(
150
+ value=cls.defaults()["classification_batch_size"],
151
+ label="Batch size (classification)",
152
+ ),
136
153
  )
137
154
 
138
155
 
@@ -144,10 +161,14 @@ class MiscInputs(InputContainer):
144
161
  end_plane: int = 0
145
162
  n_free_cpus: int = 2
146
163
  analyse_local: bool = False
164
+ use_gpu: bool = field(default_factory=lambda: torch.cuda.is_available())
165
+ pin_memory: bool = False
147
166
  debug: bool = False
148
167
 
149
168
  def as_core_arguments(self) -> dict:
150
169
  misc_input_dict = super().as_core_arguments()
170
+ misc_input_dict["torch_device"] = "cuda" if self.use_gpu else "cpu"
171
+ del misc_input_dict["use_gpu"]
151
172
  del misc_input_dict["debug"]
152
173
  del misc_input_dict["analyse_local"]
153
174
  return misc_input_dict
@@ -162,5 +183,16 @@ class MiscInputs(InputContainer):
162
183
  "n_free_cpus", custom_label="Number of free CPUs"
163
184
  ),
164
185
  analyse_local=dict(value=cls.defaults()["analyse_local"]),
186
+ use_gpu=dict(
187
+ widget_type="CheckBox",
188
+ label="Use GPU",
189
+ value=cls.defaults()["use_gpu"],
190
+ enabled=torch.cuda.is_available(),
191
+ ),
192
+ pin_memory=dict(
193
+ widget_type="CheckBox",
194
+ label="Pin data to memory",
195
+ value=cls.defaults()["pin_memory"],
196
+ ),
165
197
  debug=dict(value=cls.defaults()["debug"]),
166
198
  )
@@ -56,28 +56,35 @@ class Worker(WorkerBase):
56
56
  self.update_progress_bar.connect(update_progress_bar)
57
57
 
58
58
  def work(self) -> list:
59
- self.update_progress_bar.emit("Setting up detection...", 1, 0)
59
+ if not self.detection_inputs.skip_detection:
60
+ self.update_progress_bar.emit("Setting up detection...", 1, 0)
60
61
 
61
62
  def detect_callback(plane: int) -> None:
62
- self.update_progress_bar.emit(
63
- "Detecting cells",
64
- self.data_inputs.nplanes,
65
- plane + 1,
66
- )
63
+ if not self.detection_inputs.skip_detection:
64
+ self.update_progress_bar.emit(
65
+ "Detecting cells",
66
+ self.data_inputs.nplanes,
67
+ plane + 1,
68
+ )
67
69
 
68
70
  def detect_finished_callback(points: list) -> None:
69
71
  self.npoints_detected = len(points)
70
- self.update_progress_bar.emit("Setting up classification...", 1, 0)
72
+ if not self.classification_inputs.skip_classification:
73
+ self.update_progress_bar.emit(
74
+ "Setting up classification...", 1, 0
75
+ )
71
76
 
72
77
  def classify_callback(batch: int) -> None:
73
- self.update_progress_bar.emit(
74
- "Classifying cells",
75
- # Default cellfinder-core batch size is 64. This seems to give
76
- # a slight underestimate of the number of batches though, so
77
- # allow for batch number to go over this
78
- max(self.npoints_detected // 64 + 1, batch + 1),
79
- batch + 1,
80
- )
78
+ if not self.classification_inputs.skip_classification:
79
+ self.update_progress_bar.emit(
80
+ "Classifying cells",
81
+ # Default cellfinder-core batch size is 64.
82
+ # This seems to give a slight
83
+ # underestimate of the number of batches though,
84
+ # so allow for batch number to go over this
85
+ max(self.npoints_detected // 64 + 1, batch + 1),
86
+ batch + 1,
87
+ )
81
88
 
82
89
  result = cellfinder_run(
83
90
  **self.data_inputs.as_core_arguments(),
@@ -88,5 +95,8 @@ class Worker(WorkerBase):
88
95
  classify_callback=classify_callback,
89
96
  detect_finished_callback=detect_finished_callback,
90
97
  )
91
- self.update_progress_bar.emit("Finished classification", 1, 1)
98
+ if not self.classification_inputs.skip_classification:
99
+ self.update_progress_bar.emit("Finished classification", 1, 1)
100
+ else:
101
+ self.update_progress_bar.emit("Finished detection", 1, 1)
92
102
  return result
@@ -1,8 +1,18 @@
1
1
  from abc import abstractmethod
2
- from dataclasses import asdict, dataclass
2
+ from dataclasses import dataclass, fields
3
3
  from typing import Optional
4
4
 
5
5
 
6
+ def asdict_no_copy(obj: dataclass) -> dict:
7
+ """
8
+ Similar to `asdict`, except it makes no copies of the field values.
9
+ asdict will do a deep copy of field values that are non-basic objects.
10
+
11
+ It still creates a new dict to return, though.
12
+ """
13
+ return {field.name: getattr(obj, field.name) for field in fields(obj)}
14
+
15
+
6
16
  @dataclass
7
17
  class InputContainer:
8
18
  """Base for classes that contain inputs
@@ -23,7 +33,7 @@ class InputContainer:
23
33
  # Derived classes are not expected to be particularly
24
34
  # slow to instantiate, so use the default constructor
25
35
  # to avoid code repetition.
26
- return asdict(cls())
36
+ return asdict_no_copy(cls())
27
37
 
28
38
  @abstractmethod
29
39
  def as_core_arguments(self) -> dict:
@@ -32,10 +42,10 @@ class InputContainer:
32
42
  The implementation provided here can be re-used in derived classes, if
33
43
  convenient.
34
44
  """
35
- # note that asdict returns a new instance of a dict,
45
+ # note that asdict_no_copy returns a new instance of a dict,
36
46
  # so any subsequent modifications of this dict won't affect the class
37
47
  # instance
38
- return asdict(self)
48
+ return asdict_no_copy(self)
39
49
 
40
50
  @classmethod
41
51
  def _custom_widget(
@@ -7,7 +7,7 @@ from napari.qt.threading import thread_worker
7
7
  from napari.utils.notifications import show_info
8
8
  from qtpy.QtWidgets import QScrollArea
9
9
 
10
- from cellfinder.core.train.train_yml import run as train_yml
10
+ from cellfinder.core.train.train_yaml import run as train_yaml
11
11
  from cellfinder.napari.utils import cellfinder_header, html_label_widget
12
12
 
13
13
  from .train_containers import (
@@ -25,14 +25,14 @@ def run_training(
25
25
  optional_training_inputs: OptionalTrainingInputs,
26
26
  misc_training_inputs: MiscTrainingInputs,
27
27
  ):
28
- print("Running training")
29
- train_yml(
28
+ show_info("Running training...")
29
+ train_yaml(
30
30
  **training_data_inputs.as_core_arguments(),
31
31
  **optional_network_inputs.as_core_arguments(),
32
32
  **optional_training_inputs.as_core_arguments(),
33
33
  **misc_training_inputs.as_core_arguments(),
34
34
  )
35
- print("Finished!")
35
+ show_info("Training finished!")
36
36
 
37
37
 
38
38
  def training_widget() -> FunctionGui:
@@ -60,7 +60,6 @@ def training_widget() -> FunctionGui:
60
60
  continue_training: bool,
61
61
  augment: bool,
62
62
  tensorboard: bool,
63
- save_weights: bool,
64
63
  save_checkpoints: bool,
65
64
  save_progress: bool,
66
65
  epochs: int,
@@ -96,9 +95,6 @@ def training_widget() -> FunctionGui:
96
95
  Augment the training data to improve generalisation
97
96
  tensorboard : bool
98
97
  Log to output_directory/tensorboard
99
- save_weights : bool
100
- Only store the model weights, and not the full model
101
- Useful to save storage space
102
98
  save_checkpoints : bool
103
99
  Store the model at intermediate points during training
104
100
  save_progress : bool
@@ -133,7 +129,6 @@ def training_widget() -> FunctionGui:
133
129
  continue_training,
134
130
  augment,
135
131
  tensorboard,
136
- save_weights,
137
132
  save_checkpoints,
138
133
  save_progress,
139
134
  epochs,
@@ -147,6 +142,7 @@ def training_widget() -> FunctionGui:
147
142
  if yaml_files[0] == Path.home(): # type: ignore
148
143
  show_info("Please select a YAML file for training")
149
144
  else:
145
+ show_info("Starting training process...")
150
146
  worker = run_training(
151
147
  training_data_inputs,
152
148
  optional_network_inputs,
@@ -5,7 +5,7 @@ from typing import Optional
5
5
  from magicgui.types import FileDialogMode
6
6
 
7
7
  from cellfinder.core.download.download import model_filenames
8
- from cellfinder.core.train.train_yml import models
8
+ from cellfinder.core.train.train_yaml import models
9
9
  from cellfinder.napari.input_container import InputContainer
10
10
  from cellfinder.napari.utils import html_label_widget
11
11
 
@@ -31,7 +31,7 @@ class TrainingDataInputs(InputContainer):
31
31
  "yaml_files",
32
32
  custom_label="YAML files",
33
33
  mode=FileDialogMode.EXISTING_FILES,
34
- filter="*.yml",
34
+ filter="*.yaml",
35
35
  ),
36
36
  output_directory=cls._custom_widget(
37
37
  "output_directory", mode=FileDialogMode.EXISTING_DIRECTORY
@@ -75,7 +75,6 @@ class OptionalTrainingInputs(InputContainer):
75
75
  continue_training: bool = False
76
76
  augment: bool = True
77
77
  tensorboard: bool = False
78
- save_weights: bool = False
79
78
  save_checkpoints: bool = True
80
79
  save_progress: bool = True
81
80
  epochs: int = 100
@@ -98,7 +97,6 @@ class OptionalTrainingInputs(InputContainer):
98
97
  continue_training=cls._custom_widget("continue_training"),
99
98
  augment=cls._custom_widget("augment"),
100
99
  tensorboard=cls._custom_widget("tensorboard"),
101
- save_weights=cls._custom_widget("save_weights"),
102
100
  save_checkpoints=cls._custom_widget("save_checkpoints"),
103
101
  save_progress=cls._custom_widget("save_progress"),
104
102
  epochs=cls._custom_widget("epochs"),
@@ -1,4 +1,4 @@
1
- from typing import List, Tuple
1
+ from typing import List, Optional, Tuple
2
2
 
3
3
  import napari
4
4
  import napari.layers
@@ -44,6 +44,7 @@ def add_classified_layers(
44
44
  viewer: napari.Viewer,
45
45
  unknown_name: str = "Rejected",
46
46
  cell_name: str = "Detected",
47
+ scale: Optional[Tuple[float, float, float]] = None,
47
48
  ) -> None:
48
49
  """
49
50
  Adds cell candidates as two separate point layers - unknowns and cells, to
@@ -60,6 +61,7 @@ def add_classified_layers(
60
61
  face_color="lightskyblue",
61
62
  visible=False,
62
63
  metadata=dict(point_type=Cell.UNKNOWN),
64
+ scale=scale,
63
65
  )
64
66
  viewer.add_points(
65
67
  cells_to_array(points, Cell.CELL, napari_order=True),
@@ -70,6 +72,7 @@ def add_classified_layers(
70
72
  symbol="ring",
71
73
  face_color="lightgoldenrodyellow",
72
74
  metadata=dict(point_type=Cell.CELL),
75
+ scale=scale,
73
76
  )
74
77
 
75
78
 
@@ -78,6 +81,7 @@ def add_single_layer(
78
81
  viewer: napari.Viewer,
79
82
  name: str,
80
83
  cell_type: int,
84
+ scale: Optional[Tuple[float, float, float]] = None,
81
85
  ) -> None:
82
86
  """
83
87
  Adds all cells of cell_type Cell.TYPE to a new point layer in the napari
@@ -93,6 +97,7 @@ def add_single_layer(
93
97
  face_color="lightskyblue",
94
98
  visible=True,
95
99
  metadata=dict(point_type=cell_type),
100
+ scale=scale,
96
101
  )
97
102
 
98
103
 
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: cellfinder
3
- Version: 1.4.1
3
+ Version: 1.9.0
4
4
  Summary: Automated 3D cell detection in large microscopy images
5
5
  Author-email: "Adam Tyson, Christian Niedworok, Charly Rousseau" <code@adamltyson.com>
6
6
  License: BSD-3-Clause
@@ -16,26 +16,27 @@ Classifier: Intended Audience :: Science/Research
16
16
  Classifier: Operating System :: OS Independent
17
17
  Classifier: Programming Language :: Python
18
18
  Classifier: Programming Language :: Python :: 3
19
- Classifier: Programming Language :: Python :: 3.10
20
19
  Classifier: Programming Language :: Python :: 3.11
21
20
  Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
22
  Classifier: Topic :: Scientific/Engineering :: Image Recognition
23
- Requires-Python: >=3.10
23
+ Requires-Python: >=3.11
24
24
  Description-Content-Type: text/markdown
25
25
  License-File: LICENSE
26
26
  Requires-Dist: brainglobe-utils>=0.5.0
27
27
  Requires-Dist: brainglobe-napari-io>=0.3.4
28
28
  Requires-Dist: dask[array]
29
- Requires-Dist: fancylog>=0.0.7
29
+ Requires-Dist: fancylog>=0.6.0
30
30
  Requires-Dist: natsort
31
31
  Requires-Dist: numba
32
32
  Requires-Dist: numpy
33
33
  Requires-Dist: scikit-image
34
34
  Requires-Dist: scikit-learn
35
35
  Requires-Dist: keras>=3.7.0
36
- Requires-Dist: torch!=2.4,>=2.1.0
36
+ Requires-Dist: torch>=2.4.1
37
37
  Requires-Dist: tifffile
38
38
  Requires-Dist: tqdm
39
+ Requires-Dist: qt-niu
39
40
  Provides-Extra: dev
40
41
  Requires-Dist: black; extra == "dev"
41
42
  Requires-Dist: pre-commit; extra == "dev"
@@ -52,23 +53,26 @@ Requires-Dist: brainglobe-napari-io; extra == "napari"
52
53
  Requires-Dist: magicgui; extra == "napari"
53
54
  Requires-Dist: napari-ndtiffs; extra == "napari"
54
55
  Requires-Dist: napari-plugin-engine>=0.1.4; extra == "napari"
55
- Requires-Dist: napari[pyqt5]; extra == "napari"
56
+ Requires-Dist: napari[pyqt5]>=0.6.5; extra == "napari"
56
57
  Requires-Dist: pooch>=1; extra == "napari"
57
58
  Requires-Dist: qtpy; extra == "napari"
59
+ Dynamic: license-file
58
60
 
59
61
  [![Python Version](https://img.shields.io/pypi/pyversions/cellfinder.svg)](https://pypi.org/project/cellfinder)
60
62
  [![PyPI](https://img.shields.io/pypi/v/cellfinder.svg)](https://pypi.org/project/cellfinder)
61
- [![Downloads](https://pepy.tech/badge/cellfinder)](https://pepy.tech/project/cellfinder)
63
+ [![Anaconda version](https://anaconda.org/conda-forge/cellfinder/badges/version.svg)](https://anaconda.org/conda-forge/cellfinder)
64
+ [![Napari hub](https://img.shields.io/endpoint?url=https://npe2api-git-add-shields-napari.vercel.app/api/shields/cellfinder)](https://napari-hub.org/plugins/cellfinder.html)
65
+ [![PyPI Downloads](https://pepy.tech/badge/cellfinder)](https://pepy.tech/project/cellfinder)
62
66
  [![Wheel](https://img.shields.io/pypi/wheel/cellfinder.svg)](https://pypi.org/project/cellfinder)
63
67
  [![Development Status](https://img.shields.io/pypi/status/cellfinder.svg)](https://github.com/brainglobe/cellfinder)
64
68
  [![Tests](https://img.shields.io/github/actions/workflow/status/brainglobe/cellfinder/test_and_deploy.yml?branch=main)](https://github.com/brainglobe/cellfinder/actions)
65
69
  [![codecov](https://codecov.io/gh/brainglobe/cellfinder/branch/main/graph/badge.svg?token=nx1lhNI7ox)](https://codecov.io/gh/brainglobe/cellfinder)
66
- [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/python/black)
67
- [![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://pycqa.github.io/isort/)
70
+ [![Code style: Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/format.json)](https://github.com/astral-sh/ruff)[![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://pycqa.github.io/isort/)
68
71
  [![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)](https://github.com/pre-commit/pre-commit)
69
72
  [![Contributions](https://img.shields.io/badge/Contributions-Welcome-brightgreen.svg)](https://brainglobe.info/community/developers/index.html)
70
- [![Twitter](https://img.shields.io/twitter/follow/brain_globe?style=social)](https://twitter.com/brain_globe)
71
-
73
+ [![image.sc forum](https://img.shields.io/badge/dynamic/json.svg?label=forum&url=https%3A%2F%2Fforum.image.sc%2Ftags%2Fbrainglobe.json&query=%24.topic_list.tags.0.topic_count&colorB=brightgreen&suffix=%20topics&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAABPklEQVR42m3SyyqFURTA8Y2BER0TDyExZ+aSPIKUlPIITFzKeQWXwhBlQrmFgUzMMFLKZeguBu5y+//17dP3nc5vuPdee6299gohUYYaDGOyyACq4JmQVoFujOMR77hNfOAGM+hBOQqB9TjHD36xhAa04RCuuXeKOvwHVWIKL9jCK2bRiV284QgL8MwEjAneeo9VNOEaBhzALGtoRy02cIcWhE34jj5YxgW+E5Z4iTPkMYpPLCNY3hdOYEfNbKYdmNngZ1jyEzw7h7AIb3fRTQ95OAZ6yQpGYHMMtOTgouktYwxuXsHgWLLl+4x++Kx1FJrjLTagA77bTPvYgw1rRqY56e+w7GNYsqX6JfPwi7aR+Y5SA+BXtKIRfkfJAYgj14tpOF6+I46c4/cAM3UhM3JxyKsxiOIhH0IO6SH/A1Kb1WBeUjbkAAAAAElFTkSuQmCC)](https://forum.image.sc/tag/brainglobe)
74
+ [![Bluesky](https://img.shields.io/badge/Bluesky-0285FF?logo=bluesky&logoColor=fff)](https://bsky.app/profile/brainglobe.info)
75
+ [![Mastodon](https://img.shields.io/badge/Mastodon-6364FF?logo=mastodon&logoColor=fff)](https://mastodon.online/@brainglobe)
72
76
  # cellfinder
73
77
 
74
78
  cellfinder is software for automated 3D cell detection in very large 3D images (e.g., serial two-photon or lightsheet volumes of whole mouse brains).