cellfinder 1.3.3__tar.gz → 1.4.0__tar.gz

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 (81) hide show
  1. {cellfinder-1.3.3 → cellfinder-1.4.0}/.github/workflows/test_and_deploy.yml +48 -7
  2. {cellfinder-1.3.3 → cellfinder-1.4.0}/PKG-INFO +5 -4
  3. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder/core/classify/classify.py +3 -2
  4. cellfinder-1.4.0/cellfinder/core/detect/detect.py +236 -0
  5. cellfinder-1.4.0/cellfinder/core/detect/filters/plane/classical_filter.py +347 -0
  6. cellfinder-1.4.0/cellfinder/core/detect/filters/plane/plane_filter.py +169 -0
  7. cellfinder-1.4.0/cellfinder/core/detect/filters/plane/tile_walker.py +154 -0
  8. cellfinder-1.4.0/cellfinder/core/detect/filters/setup_filters.py +427 -0
  9. cellfinder-1.4.0/cellfinder/core/detect/filters/volume/ball_filter.py +415 -0
  10. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder/core/detect/filters/volume/structure_detection.py +73 -35
  11. cellfinder-1.4.0/cellfinder/core/detect/filters/volume/structure_splitting.py +306 -0
  12. cellfinder-1.4.0/cellfinder/core/detect/filters/volume/volume_filter.py +523 -0
  13. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder/core/main.py +6 -2
  14. cellfinder-1.4.0/cellfinder/core/tools/IO.py +45 -0
  15. cellfinder-1.4.0/cellfinder/core/tools/threading.py +380 -0
  16. cellfinder-1.4.0/cellfinder/core/tools/tools.py +295 -0
  17. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder.egg-info/PKG-INFO +5 -4
  18. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder.egg-info/SOURCES.txt +2 -0
  19. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder.egg-info/requires.txt +3 -2
  20. {cellfinder-1.3.3 → cellfinder-1.4.0}/pyproject.toml +5 -2
  21. cellfinder-1.3.3/cellfinder/core/detect/detect.py +0 -301
  22. cellfinder-1.3.3/cellfinder/core/detect/filters/plane/classical_filter.py +0 -45
  23. cellfinder-1.3.3/cellfinder/core/detect/filters/plane/plane_filter.py +0 -87
  24. cellfinder-1.3.3/cellfinder/core/detect/filters/plane/tile_walker.py +0 -88
  25. cellfinder-1.3.3/cellfinder/core/detect/filters/setup_filters.py +0 -70
  26. cellfinder-1.3.3/cellfinder/core/detect/filters/volume/ball_filter.py +0 -417
  27. cellfinder-1.3.3/cellfinder/core/detect/filters/volume/structure_splitting.py +0 -242
  28. cellfinder-1.3.3/cellfinder/core/detect/filters/volume/volume_filter.py +0 -202
  29. cellfinder-1.3.3/cellfinder/core/tools/tools.py +0 -173
  30. {cellfinder-1.3.3 → cellfinder-1.4.0}/.github/workflows/test_include_guard.yaml +0 -0
  31. {cellfinder-1.3.3 → cellfinder-1.4.0}/.gitignore +0 -0
  32. {cellfinder-1.3.3 → cellfinder-1.4.0}/.napari/config.yml +0 -0
  33. {cellfinder-1.3.3 → cellfinder-1.4.0}/CITATION.cff +0 -0
  34. {cellfinder-1.3.3 → cellfinder-1.4.0}/LICENSE +0 -0
  35. {cellfinder-1.3.3 → cellfinder-1.4.0}/MANIFEST.in +0 -0
  36. {cellfinder-1.3.3 → cellfinder-1.4.0}/README.md +0 -0
  37. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder/__init__.py +0 -0
  38. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder/cli_migration_warning.py +0 -0
  39. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder/core/__init__.py +0 -0
  40. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder/core/classify/__init__.py +0 -0
  41. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder/core/classify/augment.py +0 -0
  42. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder/core/classify/cube_generator.py +0 -0
  43. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder/core/classify/resnet.py +0 -0
  44. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder/core/classify/tools.py +0 -0
  45. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder/core/config/__init__.py +0 -0
  46. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder/core/config/cellfinder.conf +0 -0
  47. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder/core/detect/__init__.py +0 -0
  48. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder/core/detect/filters/__init__.py +0 -0
  49. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder/core/detect/filters/plane/__init__.py +0 -0
  50. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder/core/detect/filters/volume/__init__.py +0 -0
  51. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder/core/download/__init__.py +0 -0
  52. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder/core/download/cli.py +0 -0
  53. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder/core/download/download.py +0 -0
  54. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder/core/tools/__init__.py +0 -0
  55. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder/core/tools/array_operations.py +0 -0
  56. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder/core/tools/geometry.py +0 -0
  57. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder/core/tools/image_processing.py +0 -0
  58. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder/core/tools/prep.py +0 -0
  59. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder/core/tools/source_files.py +0 -0
  60. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder/core/tools/system.py +0 -0
  61. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder/core/tools/tiff.py +0 -0
  62. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder/core/train/__init__.py +0 -0
  63. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder/core/train/train_yml.py +0 -0
  64. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder/core/types.py +0 -0
  65. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder/napari/__init__.py +0 -0
  66. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder/napari/curation.py +0 -0
  67. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder/napari/detect/__init__.py +0 -0
  68. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder/napari/detect/detect.py +0 -0
  69. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder/napari/detect/detect_containers.py +0 -0
  70. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder/napari/detect/thread_worker.py +0 -0
  71. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder/napari/input_container.py +0 -0
  72. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder/napari/napari.yaml +0 -0
  73. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder/napari/sample_data.py +0 -0
  74. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder/napari/train/__init__.py +0 -0
  75. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder/napari/train/train.py +0 -0
  76. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder/napari/train/train_containers.py +0 -0
  77. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder/napari/utils.py +0 -0
  78. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder.egg-info/dependency_links.txt +0 -0
  79. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder.egg-info/entry_points.txt +0 -0
  80. {cellfinder-1.3.3 → cellfinder-1.4.0}/cellfinder.egg-info/top_level.txt +0 -0
  81. {cellfinder-1.3.3 → cellfinder-1.4.0}/setup.cfg +0 -0
@@ -38,11 +38,14 @@ jobs:
38
38
  test:
39
39
  needs: [linting, manifest]
40
40
  name: Run package tests
41
- timeout-minutes: 60
41
+ timeout-minutes: 120
42
42
  runs-on: ${{ matrix.os }}
43
43
  env:
44
44
  KERAS_BACKEND: torch
45
45
  CELLFINDER_TEST_DEVICE: cpu
46
+ # pooch cache dir
47
+ BRAINGLOBE_TEST_DATA_DIR: "~/.pooch_cache"
48
+
46
49
  strategy:
47
50
  matrix:
48
51
  # Run all supported Python versions on linux
@@ -56,6 +59,14 @@ jobs:
56
59
  python-version: "3.12"
57
60
 
58
61
  steps:
62
+ - uses: actions/checkout@v4
63
+ - name: Cache pooch data
64
+ uses: actions/cache@v4
65
+ with:
66
+ path: "~/.pooch_cache"
67
+ # hash on conftest in case url changes
68
+ key: ${{ runner.os }}-${{ matrix.python-version }}-${{ hashFiles('**/pooch_registry.txt') }}
69
+ # Cache the tensorflow model so we don't have to remake it every time
59
70
  - name: Cache brainglobe directory
60
71
  uses: actions/cache@v3
61
72
  with:
@@ -67,7 +78,7 @@ jobs:
67
78
  - name: Setup qtpy libraries
68
79
  uses: tlambert03/setup-qt-libs@v1
69
80
  # Setup VTK with headless display
70
- - uses: pyvista/setup-headless-display-action@v2
81
+ - uses: pyvista/setup-headless-display-action@v3
71
82
  # Run all tests
72
83
  - uses: neuroinformatics-unit/actions/test@v2
73
84
  with:
@@ -75,15 +86,28 @@ jobs:
75
86
  secret-codecov-token: ${{ secrets.CODECOV_TOKEN }}
76
87
  use-xvfb: true
77
88
 
89
+ - name: Notify slack on scheduled failure
90
+ if: failure() && github.event_name == 'schedule'
91
+ uses: ravsamhq/notify-slack-action@v2
92
+ with:
93
+ status: ${{ job.status }} # required
94
+ notify_when: 'failure'
95
+ env:
96
+ SLACK_WEBHOOK_URL: ${{ secrets.SLACK_NOTIFYBOT_WEBHOOK_URL }} # required
97
+
78
98
  test_numba_disabled:
79
99
  needs: [linting, manifest]
80
100
  name: Run tests with numba disabled
81
- timeout-minutes: 60
101
+ timeout-minutes: 120
82
102
  runs-on: ubuntu-latest
83
103
  env:
84
- NUMBA_DISABLE_JIT: "1"
104
+ NUMBA_DISABLE_JIT: "1"
105
+ PYTORCH_JIT: "0"
106
+ # pooch cache dir
107
+ BRAINGLOBE_TEST_DATA_DIR: "~/.pooch_cache"
85
108
 
86
109
  steps:
110
+ - uses: actions/checkout@v4
87
111
  - name: Cache brainglobe directory
88
112
  uses: actions/cache@v3
89
113
  with:
@@ -91,11 +115,18 @@ jobs:
91
115
  ~/.brainglobe
92
116
  !~/.brainglobe/atlas.tar.gz
93
117
  key: brainglobe
118
+
119
+ - name: Cache pooch data
120
+ uses: actions/cache@v4
121
+ with:
122
+ path: "~/.pooch_cache"
123
+ key: ${{ runner.os }}-3.10-${{ hashFiles('**/pooch_registry.txt') }}
124
+
94
125
  # Setup pyqt libraries
95
126
  - name: Setup qtpy libraries
96
127
  uses: tlambert03/setup-qt-libs@v1
97
128
  # Setup VTK with headless display
98
- - uses: pyvista/setup-headless-display-action@v2
129
+ - uses: pyvista/setup-headless-display-action@v3
99
130
  # Run test suite with numba disabled
100
131
  - uses: neuroinformatics-unit/actions/test@v2
101
132
  with:
@@ -103,12 +134,21 @@ jobs:
103
134
  secret-codecov-token: ${{ secrets.CODECOV_TOKEN }}
104
135
  codecov-flags: "numba"
105
136
 
137
+ - name: Notify slack on scheduled failure
138
+ if: failure() && github.event_name == 'schedule'
139
+ uses: ravsamhq/notify-slack-action@v2
140
+ with:
141
+ status: ${{ job.status }} # required
142
+ notify_when: 'failure'
143
+ env:
144
+ SLACK_WEBHOOK_URL: ${{ secrets.SLACK_NOTIFYBOT_WEBHOOK_URL }} # required
145
+
106
146
  # Run brainglobe-workflows brainmapper-CLI tests to check for
107
147
  # breakages
108
148
  test_brainmapper_cli:
109
149
  needs: [linting, manifest]
110
150
  name: Run brainmapper tests to check for breakages
111
- timeout-minutes: 60
151
+ timeout-minutes: 120
112
152
  runs-on: ubuntu-latest
113
153
  env:
114
154
  KERAS_BACKEND: torch
@@ -144,8 +184,9 @@ jobs:
144
184
  run: |
145
185
  python -m pytest --color=yes -v tests/brainmapper
146
186
 
187
+
147
188
  build_sdist_wheel:
148
- name: Build source distribution and wheel
189
+ name: Build source distribution
149
190
  needs: [test, test_numba_disabled]
150
191
  if: github.event_name == 'push' && github.ref_type == 'tag'
151
192
  runs-on: ubuntu-latest
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: cellfinder
3
- Version: 1.3.3
3
+ Version: 1.4.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
@@ -32,8 +32,8 @@ Requires-Dist: numba
32
32
  Requires-Dist: numpy
33
33
  Requires-Dist: scikit-image
34
34
  Requires-Dist: scikit-learn
35
- Requires-Dist: keras==3.5.0
36
- Requires-Dist: torch>=2.1.0
35
+ Requires-Dist: keras>=3.7.0
36
+ Requires-Dist: torch!=2.4,>=2.1.0
37
37
  Requires-Dist: tifffile
38
38
  Requires-Dist: tqdm
39
39
  Provides-Extra: dev
@@ -46,6 +46,7 @@ Requires-Dist: pytest-qt; extra == "dev"
46
46
  Requires-Dist: pytest-timeout; extra == "dev"
47
47
  Requires-Dist: pytest; extra == "dev"
48
48
  Requires-Dist: tox; extra == "dev"
49
+ Requires-Dist: pooch>=1; extra == "dev"
49
50
  Provides-Extra: napari
50
51
  Requires-Dist: brainglobe-napari-io; extra == "napari"
51
52
  Requires-Dist: magicgui; extra == "napari"
@@ -1,5 +1,6 @@
1
1
  import os
2
2
  from datetime import datetime
3
+ from pathlib import Path
3
4
  from typing import Any, Callable, Dict, List, Optional, Tuple
4
5
 
5
6
  import keras
@@ -30,7 +31,7 @@ def main(
30
31
  max_workers: int = 3,
31
32
  *,
32
33
  callback: Optional[Callable[[int], None]] = None,
33
- ) -> List:
34
+ ) -> List[Cell]:
34
35
  """
35
36
  Parameters
36
37
  ----------
@@ -68,7 +69,7 @@ def main(
68
69
  workers=workers,
69
70
  )
70
71
 
71
- if trained_model and trained_model.suffix == ".h5":
72
+ if trained_model and Path(trained_model).suffix == ".h5":
72
73
  print(
73
74
  "Weights provided in place of the model, "
74
75
  "loading weights into default model."
@@ -0,0 +1,236 @@
1
+ """
2
+ Detection is run in three steps:
3
+
4
+ 1. 2D filtering
5
+ 2. 3D filtering
6
+ 3. Structure detection
7
+
8
+ In steps 1. and 2. filters are applied, and any bright points detected
9
+ post-filter are marked. To avoid using a separate mask array to mark the
10
+ bright points, the input data is clipped to [0, (max_val - 2)]
11
+ (max_val is the maximum value that the image data type can store), and:
12
+ - (max_val - 1) is used to mark bright points during 2D filtering
13
+ - (max_val) is used to mark bright points during 3D filtering
14
+ """
15
+
16
+ import dataclasses
17
+ from datetime import datetime
18
+ from typing import Callable, List, Optional, Tuple
19
+
20
+ import numpy as np
21
+ import torch
22
+ from brainglobe_utils.cells.cells import Cell
23
+
24
+ from cellfinder.core import logger, types
25
+ from cellfinder.core.detect.filters.plane import TileProcessor
26
+ from cellfinder.core.detect.filters.setup_filters import DetectionSettings
27
+ from cellfinder.core.detect.filters.volume.volume_filter import VolumeFilter
28
+ from cellfinder.core.tools.tools import inference_wrapper
29
+
30
+
31
+ @inference_wrapper
32
+ def main(
33
+ signal_array: types.array,
34
+ start_plane: int = 0,
35
+ end_plane: int = -1,
36
+ voxel_sizes: Tuple[float, float, float] = (5, 2, 2),
37
+ soma_diameter: float = 16,
38
+ max_cluster_size: float = 100_000,
39
+ ball_xy_size: float = 6,
40
+ ball_z_size: float = 15,
41
+ ball_overlap_fraction: float = 0.6,
42
+ soma_spread_factor: float = 1.4,
43
+ n_free_cpus: int = 2,
44
+ log_sigma_size: float = 0.2,
45
+ n_sds_above_mean_thresh: float = 10,
46
+ outlier_keep: bool = False,
47
+ artifact_keep: bool = False,
48
+ save_planes: bool = False,
49
+ plane_directory: Optional[str] = None,
50
+ batch_size: Optional[int] = None,
51
+ torch_device: str = "cpu",
52
+ use_scipy: bool = True,
53
+ split_ball_xy_size: int = 3,
54
+ split_ball_z_size: int = 3,
55
+ split_ball_overlap_fraction: float = 0.8,
56
+ split_soma_diameter: int = 7,
57
+ *,
58
+ callback: Optional[Callable[[int], None]] = None,
59
+ ) -> List[Cell]:
60
+ """
61
+ Perform cell candidate detection on a 3D signal array.
62
+
63
+ Parameters
64
+ ----------
65
+ signal_array : numpy.ndarray
66
+ 3D array representing the signal data.
67
+
68
+ start_plane : int
69
+ Index of the starting plane for detection.
70
+
71
+ end_plane : int
72
+ Index of the ending plane for detection.
73
+
74
+ voxel_sizes : Tuple[float, float, float]
75
+ Tuple of voxel sizes in each dimension (z, y, x).
76
+
77
+ soma_diameter : float
78
+ Diameter of the soma in physical units.
79
+
80
+ max_cluster_size : float
81
+ Maximum size of a cluster in physical units.
82
+
83
+ ball_xy_size : float
84
+ Size of the XY ball used for filtering in physical units.
85
+
86
+ ball_z_size : float
87
+ Size of the Z ball used for filtering in physical units.
88
+
89
+ ball_overlap_fraction : float
90
+ Fraction of overlap allowed between balls.
91
+
92
+ soma_spread_factor : float
93
+ Spread factor for soma size.
94
+
95
+ n_free_cpus : int
96
+ Number of free CPU cores available for parallel processing.
97
+
98
+ log_sigma_size : float
99
+ Size of the sigma for the log filter.
100
+
101
+ n_sds_above_mean_thresh : float
102
+ Number of standard deviations above the mean threshold.
103
+
104
+ outlier_keep : bool, optional
105
+ Whether to keep outliers during detection. Defaults to False.
106
+
107
+ artifact_keep : bool, optional
108
+ Whether to keep artifacts during detection. Defaults to False.
109
+
110
+ save_planes : bool, optional
111
+ Whether to save the planes during detection. Defaults to False.
112
+
113
+ plane_directory : str, optional
114
+ Directory path to save the planes. Defaults to None.
115
+
116
+ batch_size : int, optional
117
+ The number of planes to process in each batch. Defaults to 1.
118
+ For CPU, there's no benefit for a larger batch size. Only a memory
119
+ usage increase. For CUDA, the larger the batch size the better the
120
+ performance. Until it fills up the GPU memory - after which it
121
+ becomes slower.
122
+
123
+ torch_device : str, optional
124
+ The device on which to run the computation. By default, it's "cpu".
125
+ To run on a gpu, specify the PyTorch device name, such as "cuda" to
126
+ run on the first GPU.
127
+
128
+ callback : Callable[int], optional
129
+ A callback function that is called every time a plane has finished
130
+ being processed. Called with the plane number that has finished.
131
+
132
+ Returns
133
+ -------
134
+ List[Cell]
135
+ List of detected cells.
136
+ """
137
+ start_time = datetime.now()
138
+ if batch_size is None:
139
+ if torch_device == "cpu":
140
+ batch_size = 4
141
+ else:
142
+ batch_size = 1
143
+
144
+ if not np.issubdtype(signal_array.dtype, np.number):
145
+ raise TypeError(
146
+ "signal_array must be a numpy datatype, but has datatype "
147
+ f"{signal_array.dtype}"
148
+ )
149
+
150
+ if signal_array.ndim != 3:
151
+ raise ValueError("Input data must be 3D")
152
+
153
+ if end_plane < 0:
154
+ end_plane = len(signal_array)
155
+ end_plane = min(len(signal_array), end_plane)
156
+
157
+ torch_device = torch_device.lower()
158
+ batch_size = max(batch_size, 1)
159
+ # brainmapper can pass them in as str
160
+ voxel_sizes = list(map(float, voxel_sizes))
161
+
162
+ settings = DetectionSettings(
163
+ plane_shape=signal_array.shape[1:],
164
+ plane_original_np_dtype=signal_array.dtype,
165
+ voxel_sizes=voxel_sizes,
166
+ soma_spread_factor=soma_spread_factor,
167
+ soma_diameter_um=soma_diameter,
168
+ max_cluster_size_um3=max_cluster_size,
169
+ ball_xy_size_um=ball_xy_size,
170
+ ball_z_size_um=ball_z_size,
171
+ start_plane=start_plane,
172
+ end_plane=end_plane,
173
+ n_free_cpus=n_free_cpus,
174
+ ball_overlap_fraction=ball_overlap_fraction,
175
+ log_sigma_size=log_sigma_size,
176
+ n_sds_above_mean_thresh=n_sds_above_mean_thresh,
177
+ outlier_keep=outlier_keep,
178
+ artifact_keep=artifact_keep,
179
+ save_planes=save_planes,
180
+ plane_directory=plane_directory,
181
+ batch_size=batch_size,
182
+ torch_device=torch_device,
183
+ )
184
+
185
+ # replicate the settings specific to splitting, before we access anything
186
+ # of the original settings, causing cached properties
187
+ kwargs = dataclasses.asdict(settings)
188
+ kwargs["ball_z_size_um"] = split_ball_z_size * settings.z_pixel_size
189
+ kwargs["ball_xy_size_um"] = (
190
+ split_ball_xy_size * settings.in_plane_pixel_size
191
+ )
192
+ kwargs["ball_overlap_fraction"] = split_ball_overlap_fraction
193
+ kwargs["soma_diameter_um"] = (
194
+ split_soma_diameter * settings.in_plane_pixel_size
195
+ )
196
+ # always run on cpu because copying to gpu overhead is likely slower than
197
+ # any benefit for detection on smallish volumes
198
+ kwargs["torch_device"] = "cpu"
199
+ # for splitting, we only do 3d filtering. Its input is a zero volume
200
+ # with cell voxels marked with threshold_value. So just use float32
201
+ # for input because the filters will also use float(32). So there will
202
+ # not be need to convert the input a different dtype before passing to
203
+ # the filters.
204
+ kwargs["plane_original_np_dtype"] = np.float32
205
+ splitting_settings = DetectionSettings(**kwargs)
206
+
207
+ # Create 3D analysis filter
208
+ mp_3d_filter = VolumeFilter(settings=settings)
209
+
210
+ # Create 2D analysis filter
211
+ mp_tile_processor = TileProcessor(
212
+ plane_shape=settings.plane_shape,
213
+ clipping_value=settings.clipping_value,
214
+ threshold_value=settings.threshold_value,
215
+ n_sds_above_mean_thresh=n_sds_above_mean_thresh,
216
+ log_sigma_size=log_sigma_size,
217
+ soma_diameter=settings.soma_diameter,
218
+ torch_device=torch_device,
219
+ dtype=settings.filtering_dtype.__name__,
220
+ use_scipy=use_scipy,
221
+ )
222
+
223
+ orig_n_threads = torch.get_num_threads()
224
+ torch.set_num_threads(settings.n_torch_comp_threads)
225
+
226
+ # process the data
227
+ mp_3d_filter.process(mp_tile_processor, signal_array, callback=callback)
228
+ cells = mp_3d_filter.get_results(splitting_settings)
229
+
230
+ torch.set_num_threads(orig_n_threads)
231
+
232
+ time_elapsed = datetime.now() - start_time
233
+ s = f"Detection complete. Found {len(cells)} cells in {time_elapsed}"
234
+ logger.debug(s)
235
+ print(s)
236
+ return cells