cellfinder 1.3.2__tar.gz → 1.4.0a0__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.
Potentially problematic release.
This version of cellfinder might be problematic. Click here for more details.
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/.github/workflows/test_and_deploy.yml +30 -7
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/PKG-INFO +5 -4
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder/core/classify/classify.py +9 -1
- cellfinder-1.4.0a0/cellfinder/core/detect/detect.py +236 -0
- cellfinder-1.4.0a0/cellfinder/core/detect/filters/plane/classical_filter.py +347 -0
- cellfinder-1.4.0a0/cellfinder/core/detect/filters/plane/plane_filter.py +169 -0
- cellfinder-1.4.0a0/cellfinder/core/detect/filters/plane/tile_walker.py +154 -0
- cellfinder-1.4.0a0/cellfinder/core/detect/filters/setup_filters.py +427 -0
- cellfinder-1.4.0a0/cellfinder/core/detect/filters/volume/ball_filter.py +415 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder/core/detect/filters/volume/structure_detection.py +73 -35
- cellfinder-1.4.0a0/cellfinder/core/detect/filters/volume/structure_splitting.py +306 -0
- cellfinder-1.4.0a0/cellfinder/core/detect/filters/volume/volume_filter.py +523 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder/core/main.py +6 -2
- cellfinder-1.4.0a0/cellfinder/core/tools/IO.py +45 -0
- cellfinder-1.4.0a0/cellfinder/core/tools/threading.py +380 -0
- cellfinder-1.4.0a0/cellfinder/core/tools/tools.py +295 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder.egg-info/PKG-INFO +5 -4
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder.egg-info/SOURCES.txt +2 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder.egg-info/requires.txt +4 -3
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/pyproject.toml +6 -3
- cellfinder-1.3.2/cellfinder/core/detect/detect.py +0 -301
- cellfinder-1.3.2/cellfinder/core/detect/filters/plane/classical_filter.py +0 -45
- cellfinder-1.3.2/cellfinder/core/detect/filters/plane/plane_filter.py +0 -87
- cellfinder-1.3.2/cellfinder/core/detect/filters/plane/tile_walker.py +0 -88
- cellfinder-1.3.2/cellfinder/core/detect/filters/setup_filters.py +0 -70
- cellfinder-1.3.2/cellfinder/core/detect/filters/volume/ball_filter.py +0 -417
- cellfinder-1.3.2/cellfinder/core/detect/filters/volume/structure_splitting.py +0 -242
- cellfinder-1.3.2/cellfinder/core/detect/filters/volume/volume_filter.py +0 -202
- cellfinder-1.3.2/cellfinder/core/tools/tools.py +0 -173
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/.github/workflows/test_include_guard.yaml +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/.gitignore +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/.napari/config.yml +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/CITATION.cff +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/LICENSE +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/MANIFEST.in +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/README.md +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder/__init__.py +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder/cli_migration_warning.py +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder/core/__init__.py +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder/core/classify/__init__.py +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder/core/classify/augment.py +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder/core/classify/cube_generator.py +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder/core/classify/resnet.py +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder/core/classify/tools.py +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder/core/config/__init__.py +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder/core/config/cellfinder.conf +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder/core/detect/__init__.py +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder/core/detect/filters/__init__.py +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder/core/detect/filters/plane/__init__.py +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder/core/detect/filters/volume/__init__.py +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder/core/download/__init__.py +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder/core/download/cli.py +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder/core/download/download.py +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder/core/tools/__init__.py +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder/core/tools/array_operations.py +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder/core/tools/geometry.py +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder/core/tools/image_processing.py +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder/core/tools/prep.py +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder/core/tools/source_files.py +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder/core/tools/system.py +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder/core/tools/tiff.py +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder/core/train/__init__.py +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder/core/train/train_yml.py +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder/core/types.py +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder/napari/__init__.py +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder/napari/curation.py +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder/napari/detect/__init__.py +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder/napari/detect/detect.py +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder/napari/detect/detect_containers.py +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder/napari/detect/thread_worker.py +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder/napari/input_container.py +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder/napari/napari.yaml +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder/napari/sample_data.py +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder/napari/train/__init__.py +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder/napari/train/train.py +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder/napari/train/train_containers.py +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder/napari/utils.py +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder.egg-info/dependency_links.txt +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder.egg-info/entry_points.txt +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/cellfinder.egg-info/top_level.txt +0 -0
- {cellfinder-1.3.2 → cellfinder-1.4.0a0}/setup.cfg +0 -0
|
@@ -9,6 +9,9 @@ on:
|
|
|
9
9
|
- "v**"
|
|
10
10
|
# Run on all pull-requests
|
|
11
11
|
pull_request:
|
|
12
|
+
schedule:
|
|
13
|
+
# Runs at 6:10am UTC on Monday
|
|
14
|
+
- cron: '10 6 * * 1'
|
|
12
15
|
# Allow workflow dispatch from GitHub
|
|
13
16
|
workflow_dispatch:
|
|
14
17
|
|
|
@@ -35,26 +38,35 @@ jobs:
|
|
|
35
38
|
test:
|
|
36
39
|
needs: [linting, manifest]
|
|
37
40
|
name: Run package tests
|
|
38
|
-
timeout-minutes:
|
|
41
|
+
timeout-minutes: 120
|
|
39
42
|
runs-on: ${{ matrix.os }}
|
|
40
43
|
env:
|
|
41
44
|
KERAS_BACKEND: torch
|
|
42
45
|
CELLFINDER_TEST_DEVICE: cpu
|
|
46
|
+
# pooch cache dir
|
|
47
|
+
BRAINGLOBE_TEST_DATA_DIR: "~/.pooch_cache"
|
|
48
|
+
|
|
43
49
|
strategy:
|
|
44
50
|
matrix:
|
|
45
51
|
# Run all supported Python versions on linux
|
|
46
52
|
os: [ubuntu-latest]
|
|
47
53
|
python-version: ["3.10", "3.11", "3.12"]
|
|
48
|
-
# Include one windows and
|
|
54
|
+
# Include one windows and one macOS (arm based) run
|
|
49
55
|
include:
|
|
50
|
-
- os: macos-13
|
|
51
|
-
python-version: "3.12"
|
|
52
56
|
- os: macos-latest
|
|
53
57
|
python-version: "3.12"
|
|
54
58
|
- os: windows-latest
|
|
55
59
|
python-version: "3.12"
|
|
56
60
|
|
|
57
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
|
|
58
70
|
- name: Cache brainglobe directory
|
|
59
71
|
uses: actions/cache@v3
|
|
60
72
|
with:
|
|
@@ -77,12 +89,16 @@ jobs:
|
|
|
77
89
|
test_numba_disabled:
|
|
78
90
|
needs: [linting, manifest]
|
|
79
91
|
name: Run tests with numba disabled
|
|
80
|
-
timeout-minutes:
|
|
92
|
+
timeout-minutes: 120
|
|
81
93
|
runs-on: ubuntu-latest
|
|
82
94
|
env:
|
|
83
|
-
|
|
95
|
+
NUMBA_DISABLE_JIT: "1"
|
|
96
|
+
PYTORCH_JIT: "0"
|
|
97
|
+
# pooch cache dir
|
|
98
|
+
BRAINGLOBE_TEST_DATA_DIR: "~/.pooch_cache"
|
|
84
99
|
|
|
85
100
|
steps:
|
|
101
|
+
- uses: actions/checkout@v4
|
|
86
102
|
- name: Cache brainglobe directory
|
|
87
103
|
uses: actions/cache@v3
|
|
88
104
|
with:
|
|
@@ -90,6 +106,13 @@ jobs:
|
|
|
90
106
|
~/.brainglobe
|
|
91
107
|
!~/.brainglobe/atlas.tar.gz
|
|
92
108
|
key: brainglobe
|
|
109
|
+
|
|
110
|
+
- name: Cache pooch data
|
|
111
|
+
uses: actions/cache@v4
|
|
112
|
+
with:
|
|
113
|
+
path: "~/.pooch_cache"
|
|
114
|
+
key: ${{ runner.os }}-3.10-${{ hashFiles('**/pooch_registry.txt') }}
|
|
115
|
+
|
|
93
116
|
# Setup pyqt libraries
|
|
94
117
|
- name: Setup qtpy libraries
|
|
95
118
|
uses: tlambert03/setup-qt-libs@v1
|
|
@@ -107,7 +130,7 @@ jobs:
|
|
|
107
130
|
test_brainmapper_cli:
|
|
108
131
|
needs: [linting, manifest]
|
|
109
132
|
name: Run brainmapper tests to check for breakages
|
|
110
|
-
timeout-minutes:
|
|
133
|
+
timeout-minutes: 120
|
|
111
134
|
runs-on: ubuntu-latest
|
|
112
135
|
env:
|
|
113
136
|
KERAS_BACKEND: torch
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: cellfinder
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.4.0a0
|
|
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
|
|
@@ -29,11 +29,11 @@ Requires-Dist: dask[array]
|
|
|
29
29
|
Requires-Dist: fancylog>=0.0.7
|
|
30
30
|
Requires-Dist: natsort
|
|
31
31
|
Requires-Dist: numba
|
|
32
|
-
Requires-Dist: numpy
|
|
32
|
+
Requires-Dist: numpy
|
|
33
33
|
Requires-Dist: scikit-image
|
|
34
34
|
Requires-Dist: scikit-learn
|
|
35
|
-
Requires-Dist: keras
|
|
36
|
-
Requires-Dist: torch
|
|
35
|
+
Requires-Dist: keras==3.5.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"
|
|
@@ -30,7 +30,7 @@ def main(
|
|
|
30
30
|
max_workers: int = 3,
|
|
31
31
|
*,
|
|
32
32
|
callback: Optional[Callable[[int], None]] = None,
|
|
33
|
-
) -> List:
|
|
33
|
+
) -> List[Cell]:
|
|
34
34
|
"""
|
|
35
35
|
Parameters
|
|
36
36
|
----------
|
|
@@ -68,6 +68,14 @@ def main(
|
|
|
68
68
|
workers=workers,
|
|
69
69
|
)
|
|
70
70
|
|
|
71
|
+
if trained_model and trained_model.suffix == ".h5":
|
|
72
|
+
print(
|
|
73
|
+
"Weights provided in place of the model, "
|
|
74
|
+
"loading weights into default model."
|
|
75
|
+
)
|
|
76
|
+
model_weights = trained_model
|
|
77
|
+
trained_model = None
|
|
78
|
+
|
|
71
79
|
model = get_model(
|
|
72
80
|
existing_model=trained_model,
|
|
73
81
|
model_weights=model_weights,
|
|
@@ -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
|