cindra 1.0.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 (74) hide show
  1. cindra/__init__.py +44 -0
  2. cindra/classification/__init__.py +8 -0
  3. cindra/classification/classifier.npz +0 -0
  4. cindra/classification/classify.py +363 -0
  5. cindra/dataclasses/__init__.py +76 -0
  6. cindra/dataclasses/multi_recording_configuration.py +207 -0
  7. cindra/dataclasses/multi_recording_data.py +561 -0
  8. cindra/dataclasses/runtime_contexts.py +534 -0
  9. cindra/dataclasses/single_recording_configuration.py +563 -0
  10. cindra/dataclasses/single_recording_data.py +1619 -0
  11. cindra/dataclasses/version.py +22 -0
  12. cindra/detection/__init__.py +29 -0
  13. cindra/detection/denoise.py +125 -0
  14. cindra/detection/detect.py +537 -0
  15. cindra/detection/detect_rois.py +775 -0
  16. cindra/detection/roi_statistics.py +564 -0
  17. cindra/detection/tracking.py +583 -0
  18. cindra/detection/utils.py +326 -0
  19. cindra/extraction/__init__.py +14 -0
  20. cindra/extraction/colocalization.py +389 -0
  21. cindra/extraction/deconvolve.py +237 -0
  22. cindra/extraction/extract.py +1007 -0
  23. cindra/extraction/masks.py +277 -0
  24. cindra/gui/__init__.py +15 -0
  25. cindra/gui/app.py +220 -0
  26. cindra/gui/binary_viewer.py +562 -0
  27. cindra/gui/constants.py +336 -0
  28. cindra/gui/data_models.py +99 -0
  29. cindra/gui/overlays.py +986 -0
  30. cindra/gui/pc_viewer.py +527 -0
  31. cindra/gui/roi_viewer.py +1930 -0
  32. cindra/gui/styles.py +190 -0
  33. cindra/gui/tracking_viewer.py +902 -0
  34. cindra/gui/viewer_context.py +1234 -0
  35. cindra/gui/viewer_state.py +110 -0
  36. cindra/gui/widgets.py +580 -0
  37. cindra/interface/__init__.py +3 -0
  38. cindra/interface/acquisition_tools.py +472 -0
  39. cindra/interface/cli.py +312 -0
  40. cindra/interface/configuration_tools.py +833 -0
  41. cindra/interface/gui_cli.py +114 -0
  42. cindra/interface/gui_mcp_server.py +245 -0
  43. cindra/interface/mcp_instance.py +13 -0
  44. cindra/interface/mcp_server.py +21 -0
  45. cindra/interface/processing_tools.py +2205 -0
  46. cindra/interface/results_tools.py +1696 -0
  47. cindra/io/__init__.py +30 -0
  48. cindra/io/binary.py +547 -0
  49. cindra/io/combine.py +498 -0
  50. cindra/io/context.py +603 -0
  51. cindra/io/select.py +262 -0
  52. cindra/io/tiff.py +465 -0
  53. cindra/pipelines/__init__.py +19 -0
  54. cindra/pipelines/multi_recording.py +112 -0
  55. cindra/pipelines/pipeline.py +560 -0
  56. cindra/pipelines/single_recording.py +231 -0
  57. cindra/py.typed +0 -0
  58. cindra/registration/__init__.py +16 -0
  59. cindra/registration/bidiphase_correction.py +80 -0
  60. cindra/registration/deformation.py +817 -0
  61. cindra/registration/diffeomorphic.py +497 -0
  62. cindra/registration/metrics.py +412 -0
  63. cindra/registration/nonrigid.py +576 -0
  64. cindra/registration/pyramid.py +132 -0
  65. cindra/registration/register.py +1117 -0
  66. cindra/registration/register_recordings.py +523 -0
  67. cindra/registration/rigid.py +184 -0
  68. cindra/registration/spline_grid.py +408 -0
  69. cindra/registration/utils.py +351 -0
  70. cindra-1.0.0.dist-info/METADATA +994 -0
  71. cindra-1.0.0.dist-info/RECORD +74 -0
  72. cindra-1.0.0.dist-info/WHEEL +4 -0
  73. cindra-1.0.0.dist-info/entry_points.txt +3 -0
  74. cindra-1.0.0.dist-info/licenses/LICENSE +621 -0
cindra/__init__.py ADDED
@@ -0,0 +1,44 @@
1
+ """Provides pipelines for processing neural imaging data and tracking Regions of Interest across multiple recordings.
2
+
3
+ See the `documentation <https://cindra-api-docs.netlify.app/>`_ for the description of available assets. See the
4
+ `source code repository <https://github.com/Sun-Lab-NBB/cindra>`_ for more details.
5
+
6
+ Authors: Ivan Kondratyev, Natalie Yeung
7
+ """
8
+
9
+ # Configures numba threading layer for parallel execution across all modules. This must be set before any numba
10
+ # functions are compiled, hence it appears before other imports. macOS uses OpenMP (libomp via llvm-openmp) because
11
+ # tbb4py publishes no Apple Silicon wheel; all other platforms use TBB for lower overhead on flat prange loops.
12
+ import sys
13
+
14
+ from numba import config # type: ignore[import-untyped]
15
+
16
+ config.THREADING_LAYER = "omp" if sys.platform == "darwin" else "tbb"
17
+
18
+ from ataraxis_base_utilities import console # noqa: E402
19
+
20
+ from .pipelines import ( # noqa: E402
21
+ MultiRecordingJobNames,
22
+ SingleRecordingJobNames,
23
+ run_multi_recording_pipeline,
24
+ run_single_recording_pipeline,
25
+ )
26
+ from .dataclasses import ( # noqa: E402
27
+ MultiRecordingConfiguration,
28
+ SingleRecordingConfiguration,
29
+ )
30
+
31
+ # Ensures console output is enabled whenever the cindra library is imported. The 'Console' class is
32
+ # used over 'print' for all terminal outputs. With minimal configuration, this class can be extended to log terminal
33
+ # outputs instead of or in addition to sending them to the terminal.
34
+ if not console.enabled:
35
+ console.enable()
36
+
37
+ __all__ = [
38
+ "MultiRecordingConfiguration",
39
+ "MultiRecordingJobNames",
40
+ "SingleRecordingConfiguration",
41
+ "SingleRecordingJobNames",
42
+ "run_multi_recording_pipeline",
43
+ "run_single_recording_pipeline",
44
+ ]
@@ -0,0 +1,8 @@
1
+ """Provides classification algorithms for distinguishing cells from artifacts."""
2
+
3
+ from .classify import Classifier, classify
4
+
5
+ __all__ = [
6
+ "Classifier",
7
+ "classify",
8
+ ]
Binary file
@@ -0,0 +1,363 @@
1
+ """Provides ROI classification functionality for distinguishing cells from artifacts."""
2
+
3
+ from typing import TYPE_CHECKING
4
+ from pathlib import Path
5
+ from operator import attrgetter
6
+
7
+ import numpy as np
8
+ from scipy.ndimage import gaussian_filter
9
+ from sklearn.linear_model import LogisticRegression # type: ignore[import-untyped]
10
+ from ataraxis_base_utilities import console
11
+
12
+ if TYPE_CHECKING:
13
+ from numpy.typing import NDArray
14
+
15
+ from ..dataclasses import ROIStatistics
16
+
17
+
18
+ _BUILTIN_CLASSIFIER_PATH: Path = Path(__file__).parent / "classifier.npz"
19
+ """The path to the built-in classifier bundled with cindra."""
20
+
21
+ _CLASSIFICATION_FEATURES: tuple[str, ...] = ("normalized_pixel_count", "compactness", "skewness")
22
+ """The names of the ROI features used for full classification (after signal extraction), in the order they appear in
23
+ the feature matrix."""
24
+
25
+ _PRECLASSIFICATION_FEATURES: tuple[str, ...] = ("normalized_pixel_count", "compactness")
26
+ """The names of the ROI features used for preclassification (during detection, before signal extraction). This subset
27
+ excludes skewness which requires extracted fluorescence traces to compute."""
28
+
29
+ _GRID_NODE_COUNT: int = 100
30
+ """The number of grid nodes used for probability estimation during model fitting."""
31
+
32
+ _LOG_EPSILON: float = 1e-6
33
+ """The small epsilon value added to probabilities to prevent log(0) errors."""
34
+
35
+
36
+ class Classifier:
37
+ """Provides logistic regression-based classification for identifying cell ROIs.
38
+
39
+ Loads classifier training data from the specified .npz file, fits a logistic regression model, and uses
40
+ it to predict whether detected ROIs represent real cells or artifacts based on their morphological features.
41
+
42
+ Notes:
43
+ The classifier file format uses pickle-free npz serialization containing training_labels and feature arrays
44
+ (normalized_pixel_count, compactness, skewness). The model is fitted on load, which takes approximately 10ms
45
+ for the default training set.
46
+
47
+ Args:
48
+ classifier_path: The path to a classifier .npz file containing training_labels and feature arrays.
49
+ feature_names: The tuple of feature names to use for classification. Only these features will be loaded from
50
+ the classifier file and used for model fitting. If None, all available features in the classifier file
51
+ are used.
52
+
53
+ Attributes:
54
+ _classifier_path: The path to the loaded classifier file.
55
+ _available_features: The list of feature names used by the classifier.
56
+ _training_features: A dictionary mapping feature names to their training value arrays.
57
+ _training_labels: The boolean training labels array with shape (n_samples,).
58
+ _probability_grid: The grid boundaries computed from sorted training statistics with shape
59
+ (n_nodes, n_features). Used to map input feature values to grid intervals for probability lookup
60
+ during classification.
61
+ _grid_cell_probabilities: The Gaussian-smoothed probability that an ROI is a cell for each grid interval
62
+ with shape (n_nodes - 1, n_features). Used to compute log probability ratios that serve as input
63
+ features for the logistic regression model.
64
+ _model: The fitted LogisticRegression model.
65
+ """
66
+
67
+ def __init__(self, classifier_path: Path, feature_names: tuple[str, ...] | None = None) -> None:
68
+ if not classifier_path.exists():
69
+ message = (
70
+ f"Unable to load the classification training data. The classifier file does not exist at the "
71
+ f"specified path: {classifier_path}."
72
+ )
73
+ console.error(message=message, error=FileNotFoundError)
74
+
75
+ try:
76
+ # Loads the training data.
77
+ data = np.load(classifier_path, allow_pickle=False)
78
+
79
+ if "training_labels" not in data:
80
+ message = (
81
+ f"Unable to load the classification training data. The classifier file at {classifier_path} is "
82
+ f"missing the 'training_labels' column."
83
+ )
84
+ console.error(message=message, error=ValueError)
85
+
86
+ # Resolves the labels and the training dataset size.
87
+ training_labels = data["training_labels"].astype(np.bool_)
88
+ n_samples = len(training_labels)
89
+
90
+ training_features: dict[str, NDArray[np.float32]] = {}
91
+ available_features: list[str] = []
92
+
93
+ # Determines which features to load. If feature_names is specified, only those features are used.
94
+ # Otherwise, all available features in the classifier file are used.
95
+ target_features = feature_names if feature_names is not None else _CLASSIFICATION_FEATURES
96
+
97
+ # Loads the requested features from the classifier file. As long as the dataset contains at least one
98
+ # valid feature, the class can train the model. This allows flexibly working with incomplete datasets
99
+ # and extending the feature set in the future.
100
+ for feature_name in target_features:
101
+ if feature_name in data:
102
+ feature_array = data[feature_name].astype(np.float32)
103
+ if len(feature_array) == n_samples and not np.all(np.isnan(feature_array)):
104
+ training_features[feature_name] = feature_array
105
+ available_features.append(feature_name)
106
+
107
+ if not available_features:
108
+ message = (
109
+ f"Unable to load the classification training data. The classifier file at {classifier_path} "
110
+ f"does not contain any of the expected feature columns: {', '.join(target_features)}."
111
+ )
112
+ console.error(message=message, error=ValueError)
113
+
114
+ # Sets instance attributes after all validation passes.
115
+ self._classifier_path: Path = classifier_path
116
+ self._available_features: list[str] = available_features
117
+ self._training_features: dict[str, NDArray[np.float32]] = training_features
118
+ self._training_labels: NDArray[np.bool_] = training_labels
119
+
120
+ # Fits the logistic regression model using the validated training data.
121
+ self._fit_model()
122
+
123
+ except (ValueError, KeyError, TypeError) as exception:
124
+ message = (
125
+ f"Unable to load the classification training data. The classifier file at {classifier_path} is "
126
+ f"corrupted or has an invalid format. Original loader error: {exception}."
127
+ )
128
+ console.error(message=message, error=ValueError)
129
+
130
+ def _extract_features(self, roi_statistics: list[ROIStatistics]) -> NDArray[np.float32]:
131
+ """Extracts classification features supported by the model from ROIStatistics instances.
132
+
133
+ Args:
134
+ roi_statistics: The list of ROIStatistics instances to extract features from.
135
+
136
+ Returns:
137
+ An array of shape (n_rois, n_features) containing the extracted features.
138
+ """
139
+ n_rois = len(roi_statistics)
140
+ n_features = len(self._available_features)
141
+ features = np.zeros((n_rois, n_features), dtype=np.float32)
142
+
143
+ # Pre-creates attribute accessors to avoid repeated string lookups.
144
+ getters = [attrgetter(name) for name in self._available_features]
145
+
146
+ # Extracts feature values, using NaN for missing values.
147
+ for roi_index, roi in enumerate(roi_statistics):
148
+ for feature_index, getter in enumerate(getters):
149
+ value = getter(roi)
150
+ features[roi_index, feature_index] = np.nan if value is None else value
151
+
152
+ return features
153
+
154
+ def _get_training_features(self) -> NDArray[np.float32]:
155
+ """Assembles the training feature matrix from individual feature arrays.
156
+
157
+ Returns:
158
+ An array of shape (n_samples, n_features) containing the training features.
159
+ """
160
+ feature_arrays = [self._training_features[name] for name in self._available_features]
161
+ return np.column_stack(feature_arrays)
162
+
163
+ def _compute_log_probabilities(self, features: NDArray[np.float32]) -> NDArray[np.float32]:
164
+ """Computes log probability ratios for the given features.
165
+
166
+ Args:
167
+ features: An array of shape (n_samples, n_features) containing the feature values.
168
+
169
+ Returns:
170
+ An array of shape (n_samples, n_features) containing the log probability ratios.
171
+ """
172
+ log_probabilities = np.zeros(features.shape, dtype=np.float32)
173
+
174
+ for feature_index in range(features.shape[1]):
175
+ feature_values = features[:, feature_index].copy()
176
+
177
+ # Clips feature values to the grid bounds and replaces NaN with the minimum grid value.
178
+ grid_min = self._probability_grid[0, feature_index]
179
+ grid_max = self._probability_grid[-1, feature_index]
180
+ feature_values = np.clip(feature_values, a_min=grid_min, a_max=grid_max)
181
+ feature_values[np.isnan(feature_values)] = grid_min
182
+
183
+ # Maps each feature value to its corresponding grid bin index.
184
+ bin_indices = np.digitize(feature_values, bins=self._probability_grid[:, feature_index], right=True) - 1
185
+ bin_indices = np.clip(bin_indices, a_min=0, a_max=self._grid_cell_probabilities.shape[0] - 1)
186
+
187
+ # Looks up the pre-computed cell probability for each bin and converts to log-odds.
188
+ probabilities = self._grid_cell_probabilities[bin_indices, feature_index]
189
+ log_probabilities[:, feature_index] = np.log(probabilities + _LOG_EPSILON) - np.log(
190
+ 1 - probabilities + _LOG_EPSILON
191
+ )
192
+
193
+ return log_probabilities
194
+
195
+ def _predict_probabilities(self, roi_statistics: list[ROIStatistics]) -> NDArray[np.float32]:
196
+ """Predicts the probability that each ROI in the input list is a cell.
197
+
198
+ Args:
199
+ roi_statistics: The list of ROIStatistics instances that define the ROIs to predict probabilities for.
200
+
201
+ Returns:
202
+ An array of shape (n_rois,) containing the probability that each ROI is a cell.
203
+ """
204
+ features = self._extract_features(roi_statistics=roi_statistics)
205
+ log_probabilities = self._compute_log_probabilities(features=features)
206
+ predictions = self._model.predict_proba(log_probabilities)[:, 1]
207
+
208
+ return predictions.astype(np.float32)
209
+
210
+ def _fit_model(self) -> None:
211
+ """Fits the logistic regression model using the loaded training data."""
212
+ training_features = self._get_training_features()
213
+ n_samples, n_features = training_features.shape
214
+
215
+ # Sorts features and creates evenly-spaced grid boundaries for probability estimation.
216
+ sorted_features = np.sort(training_features, axis=0)
217
+ sort_indices = np.argsort(training_features, axis=0)
218
+ grid_indices = np.linspace(start=0, stop=n_samples - 1, num=_GRID_NODE_COUNT).astype(np.intp)
219
+ self._probability_grid = sorted_features[grid_indices, :]
220
+
221
+ # Computes the fraction of cells (vs artifacts) in each grid bin for each feature.
222
+ self._grid_cell_probabilities = np.zeros((_GRID_NODE_COUNT - 1, n_features), dtype=np.float32)
223
+ bin_sizes = grid_indices[1:] - grid_indices[:-1]
224
+
225
+ for feature_index in range(n_features):
226
+ # Reorders labels by sorted feature values and computes cumulative sum.
227
+ sorted_labels = self._training_labels[sort_indices[:, feature_index]].astype(np.float32)
228
+ cumulative_sum = np.concatenate([[0], np.cumsum(sorted_labels)])
229
+
230
+ # Computes bin sums using cumulative sum differences, then converts to means.
231
+ bin_sums = cumulative_sum[grid_indices[1:]] - cumulative_sum[grid_indices[:-1]]
232
+ self._grid_cell_probabilities[:, feature_index] = bin_sums / bin_sizes
233
+
234
+ # Smooths the probability estimates across bins to reduce noise.
235
+ self._grid_cell_probabilities = gaussian_filter(self._grid_cell_probabilities, sigma=(2.0, 0)).astype(
236
+ np.float32
237
+ )
238
+
239
+ # Fits the logistic regression model using log-odds transformed features.
240
+ log_probabilities = self._compute_log_probabilities(features=training_features)
241
+ self._model = LogisticRegression(C=100.0, solver="liblinear")
242
+ self._model.fit(X=log_probabilities, y=self._training_labels)
243
+
244
+ @staticmethod
245
+ def create_training_dataset(
246
+ file_path: Path,
247
+ training_labels: NDArray[np.bool_],
248
+ normalized_pixel_count: NDArray[np.float32],
249
+ compactness: NDArray[np.float32],
250
+ skewness: NDArray[np.float32],
251
+ ) -> None:
252
+ """Creates a new classifier training dataset file from the provided labels and features.
253
+
254
+ Args:
255
+ file_path: The path where the classifier file will be saved. Should have .npz extension.
256
+ training_labels: An array of binary labels (False for artifact, True for cell) with shape (n_samples,).
257
+ normalized_pixel_count: An array of normalized pixel count values with shape (n_samples,).
258
+ compactness: An array of compactness values with shape (n_samples,).
259
+ skewness: An array of skewness values with shape (n_samples,).
260
+
261
+ Raises:
262
+ ValueError: If feature arrays have mismatched lengths.
263
+ """
264
+ n_samples = len(training_labels)
265
+
266
+ # Validates feature array lengths.
267
+ features = {
268
+ "normalized_pixel_count": normalized_pixel_count,
269
+ "compactness": compactness,
270
+ "skewness": skewness,
271
+ }
272
+ for feature_name, feature_array in features.items():
273
+ if len(feature_array) != n_samples:
274
+ message = (
275
+ f"Unable to create the classifier training dataset file. The feature '{feature_name}' has "
276
+ f"{len(feature_array)} samples, but training_labels has {n_samples} samples."
277
+ )
278
+ console.error(message=message, error=ValueError)
279
+
280
+ # Saves the training dataset.
281
+ np.savez(
282
+ file_path,
283
+ training_labels=training_labels,
284
+ normalized_pixel_count=normalized_pixel_count,
285
+ compactness=compactness,
286
+ skewness=skewness,
287
+ )
288
+
289
+ def classify(
290
+ self,
291
+ roi_statistics: list[ROIStatistics],
292
+ probability_threshold: float = 0.5,
293
+ ) -> NDArray[np.float32]:
294
+ """Classifies the ROIs as cells or non-cells based on their morphological features.
295
+
296
+ Args:
297
+ roi_statistics: The list of ROIStatistics instances that store the features of the ROIs to classify.
298
+ probability_threshold: The probability threshold above which an ROI is classified as a cell.
299
+
300
+ Returns:
301
+ An array of shape (n_rois, 2) where each row contains [is_cell, probability]. The is_cell value is 1.0
302
+ if the ROI is classified as a cell (probability > threshold) and 0.0 otherwise.
303
+
304
+ Raises:
305
+ ValueError: If the input roi_statistics list is empty.
306
+ """
307
+ if not roi_statistics:
308
+ message = "Unable to classify ROIs. The input roi_statistics list is empty."
309
+ console.error(message=message, error=ValueError)
310
+
311
+ probabilities = self._predict_probabilities(roi_statistics=roi_statistics)
312
+ is_cell = (probabilities > probability_threshold).astype(np.float32)
313
+
314
+ return np.stack([is_cell, probabilities], axis=1)
315
+
316
+
317
+ def classify(
318
+ roi_statistics: list[ROIStatistics],
319
+ classification_threshold: float = 0.5,
320
+ custom_classifier_path: Path | None = None,
321
+ preclassification: bool = False,
322
+ ) -> NDArray[np.float32]:
323
+ """Classifies detected ROIs as cells or non-cells using a logistic regression model.
324
+
325
+ Loads classifier training data from the specified file (or the built-in classifier if no custom path
326
+ is provided), fits a logistic regression model, and uses it to classify the input ROIs based on their morphological
327
+ features.
328
+
329
+ Args:
330
+ roi_statistics: The list of ROIStatistics instances containing the morphological features of the ROIs to
331
+ classify. Must contain at least one ROI.
332
+ classification_threshold: The probability threshold above which an ROI is classified as a cell. ROIs with
333
+ probabilities above this threshold are labeled as cells (1.0), others as non-cells (0.0).
334
+ custom_classifier_path: An optional path to a custom classifier .npz file. If None, the built-in classifier
335
+ bundled with cindra is used.
336
+ preclassification: Determines whether to use a 2-feature model (normalized_pixel_count, compactness) suitable
337
+ for early filtering during detection before signal extraction. When False, uses the full 3-feature model
338
+ that includes skewness computed from extracted fluorescence traces.
339
+
340
+ Returns:
341
+ An array of shape (n_rois, 2) where each row contains [is_cell, probability]. The is_cell value is 1.0 if the
342
+ ROI is classified as a cell (probability > threshold) and 0.0 otherwise.
343
+
344
+ Raises:
345
+ ValueError: If the input roi_statistics list is empty.
346
+ """
347
+ if not roi_statistics:
348
+ message = (
349
+ "Unable to classify ROIs. No ROIs appear to have been detected. Classification requires detection to "
350
+ "discover at least one valid ROI candidate."
351
+ )
352
+ console.error(message=message, error=ValueError)
353
+
354
+ # Resolves the classifier dataset to use for training the model.
355
+ classifier_path = custom_classifier_path if custom_classifier_path is not None else _BUILTIN_CLASSIFIER_PATH
356
+
357
+ # Selects the feature set based on the classification mode. Preclassification uses only morphological features
358
+ # available during detection, while full classification includes skewness from extracted fluorescence.
359
+ feature_names = _PRECLASSIFICATION_FEATURES if preclassification else _CLASSIFICATION_FEATURES
360
+
361
+ # Trains the logistic regression model (~10 ms) and uses it to classify the detected ROIs.
362
+ classifier = Classifier(classifier_path=classifier_path, feature_names=feature_names)
363
+ return classifier.classify(roi_statistics=roi_statistics, probability_threshold=classification_threshold)
@@ -0,0 +1,76 @@
1
+ """Provides configuration and runtime data classes for the single-recording and multi-recording cindra pipelines."""
2
+
3
+ from .version import version, python_version
4
+ from .runtime_contexts import RuntimeContext, MultiRecordingRuntimeContext
5
+ from .multi_recording_data import (
6
+ MultiRecordingIOData,
7
+ MultiRecordingTimingData,
8
+ MultiRecordingRuntimeData,
9
+ MultiRecordingTrackingData,
10
+ MultiRecordingRegistrationData,
11
+ )
12
+ from .single_recording_data import (
13
+ IOData,
14
+ ROIMask,
15
+ TimingData,
16
+ CombinedData,
17
+ DetectionData,
18
+ ROIStatistics,
19
+ ExtractionData,
20
+ RegistrationData,
21
+ SingleRecordingRuntimeData,
22
+ )
23
+ from .multi_recording_configuration import ReferenceImageType, MultiRecordingConfiguration
24
+ from .single_recording_configuration import (
25
+ Main,
26
+ FileIO,
27
+ PipelineType,
28
+ ROIDetection,
29
+ Registration,
30
+ BaselineMethod,
31
+ RuntimeSettings,
32
+ SignalExtraction,
33
+ SpikeDeconvolution,
34
+ NonrigidRegistration,
35
+ AcquisitionParameters,
36
+ OnePhotonRegistration,
37
+ SingleRecordingConfiguration,
38
+ detect_pipeline_type,
39
+ )
40
+
41
+ __all__ = [
42
+ "AcquisitionParameters",
43
+ "BaselineMethod",
44
+ "CombinedData",
45
+ "DetectionData",
46
+ "ExtractionData",
47
+ "FileIO",
48
+ "IOData",
49
+ "Main",
50
+ "MultiRecordingConfiguration",
51
+ "MultiRecordingIOData",
52
+ "MultiRecordingRegistrationData",
53
+ "MultiRecordingRuntimeContext",
54
+ "MultiRecordingRuntimeData",
55
+ "MultiRecordingTimingData",
56
+ "MultiRecordingTrackingData",
57
+ "NonrigidRegistration",
58
+ "OnePhotonRegistration",
59
+ "PipelineType",
60
+ "ROIDetection",
61
+ "ROIMask",
62
+ "ROIStatistics",
63
+ "ReferenceImageType",
64
+ "Registration",
65
+ "RegistrationData",
66
+ "RuntimeContext",
67
+ "RuntimeSettings",
68
+ "SignalExtraction",
69
+ "SingleRecordingConfiguration",
70
+ "SingleRecordingRuntimeData",
71
+ "SpikeDeconvolution",
72
+ "TimingData",
73
+ "detect_pipeline_type",
74
+ "python_version",
75
+ "version",
76
+ ]