align-toolbox 0.5.1__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.
- align_toolbox/__init__.py +6 -0
- align_toolbox/classification/__init__.py +5 -0
- align_toolbox/classification/classification_tools.py +679 -0
- align_toolbox/classification/qc_tools.py +134 -0
- align_toolbox/data_analysis/__init__.py +39 -0
- align_toolbox/data_analysis/growth_rate.py +382 -0
- align_toolbox/data_analysis/time_series.py +747 -0
- align_toolbox/deep_learning/__init__.py +16 -0
- align_toolbox/deep_learning/architectures/__init__.py +9 -0
- align_toolbox/deep_learning/architectures/archs.py +141 -0
- align_toolbox/deep_learning/architectures/models.py +449 -0
- align_toolbox/deep_learning/deep_learning_tools.py +249 -0
- align_toolbox/deep_learning/utils/__init__.py +0 -0
- align_toolbox/deep_learning/utils/augmentation.py +395 -0
- align_toolbox/deep_learning/utils/dataset.py +1625 -0
- align_toolbox/deep_learning/utils/loss.py +304 -0
- align_toolbox/deep_learning/utils/util.py +190 -0
- align_toolbox/foundation/__init__.py +0 -0
- align_toolbox/foundation/binary_image.py +195 -0
- align_toolbox/foundation/detect_molts.py +283 -0
- align_toolbox/foundation/file_handling.py +333 -0
- align_toolbox/foundation/image_handling.py +535 -0
- align_toolbox/foundation/image_quality.py +140 -0
- align_toolbox/foundation/keypoint_detection.py +44 -0
- align_toolbox/foundation/utils.py +181 -0
- align_toolbox/foundation/worm_features.py +772 -0
- align_toolbox/foundation/zstack.py +180 -0
- align_toolbox/plotting/__init__.py +0 -0
- align_toolbox/plotting/boxplots.py +1439 -0
- align_toolbox/plotting/curves.py +278 -0
- align_toolbox/plotting/heterogeneity.py +286 -0
- align_toolbox/plotting/images.py +424 -0
- align_toolbox/plotting/plotting_structure.py +1008 -0
- align_toolbox/plotting/proportions.py +1551 -0
- align_toolbox/plotting/utils_data_processing.py +485 -0
- align_toolbox/plotting/utils_plotting.py +344 -0
- align_toolbox/quantification/__init__.py +9 -0
- align_toolbox/quantification/quantification_tools.py +77 -0
- align_toolbox/segmentation/__init__.py +11 -0
- align_toolbox/segmentation/segmentation_tools.py +480 -0
- align_toolbox/straightening/__init__.py +5 -0
- align_toolbox/straightening/straightening_tools.py +1034 -0
- align_toolbox-0.5.1.dist-info/METADATA +90 -0
- align_toolbox-0.5.1.dist-info/RECORD +47 -0
- align_toolbox-0.5.1.dist-info/WHEEL +5 -0
- align_toolbox-0.5.1.dist-info/licenses/LICENSE +28 -0
- align_toolbox-0.5.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,679 @@
|
|
|
1
|
+
from collections.abc import Callable
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
import pandas as pd
|
|
5
|
+
import xgboost
|
|
6
|
+
from joblib import Parallel, delayed
|
|
7
|
+
|
|
8
|
+
from align_toolbox.foundation import worm_features
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def classify_image(
|
|
12
|
+
image: np.ndarray,
|
|
13
|
+
features_function: Callable,
|
|
14
|
+
classifier: xgboost.XGBClassifier,
|
|
15
|
+
classes: list,
|
|
16
|
+
**kwargs,
|
|
17
|
+
) -> str:
|
|
18
|
+
"""
|
|
19
|
+
Classify an image based on features extracted by a provided function.
|
|
20
|
+
|
|
21
|
+
Parameters:
|
|
22
|
+
image (np.ndarray): The image (or array of images) to classify.
|
|
23
|
+
features_function (callable): A function that extracts a feature vector from
|
|
24
|
+
``image``; called as ``features_function(image, **kwargs)``.
|
|
25
|
+
classifier (xgboost.XGBClassifier): Trained XGBoost classifier.
|
|
26
|
+
classes (list): Ordered list of class labels matching the classifier's output
|
|
27
|
+
columns (e.g. ``["egg", "worm", "error"]``).
|
|
28
|
+
**kwargs: Additional keyword arguments forwarded to ``features_function``.
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
str: The predicted class label (element of ``classes``).
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
# feature extraction
|
|
35
|
+
try:
|
|
36
|
+
features = features_function(image, **kwargs)
|
|
37
|
+
except Exception as e:
|
|
38
|
+
raise Exception(f"Error extracting features from image. {e}")
|
|
39
|
+
# classification
|
|
40
|
+
try:
|
|
41
|
+
prediction = classifier.predict_proba(features).squeeze()
|
|
42
|
+
except Exception as e:
|
|
43
|
+
raise Exception(f"Error predicting class of image. {e}")
|
|
44
|
+
|
|
45
|
+
assert len(prediction) == len(
|
|
46
|
+
classes
|
|
47
|
+
), f"Number of provided classes and predicted classes do not match. len(prediction) = {len(prediction)}, len(classes) = {len(classes)}"
|
|
48
|
+
# convert proba to one hot encoding
|
|
49
|
+
pred_class = np.argmax(prediction)
|
|
50
|
+
prediction = classes[pred_class]
|
|
51
|
+
return prediction
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def compute_features_of_label(
|
|
55
|
+
current_label: int,
|
|
56
|
+
mask_plane: np.ndarray,
|
|
57
|
+
image_plane: np.ndarray,
|
|
58
|
+
all_features: list[str],
|
|
59
|
+
extra_properties: list,
|
|
60
|
+
intensity_features: list[str],
|
|
61
|
+
extra_intensity_features: list,
|
|
62
|
+
num_closest: int | None = None,
|
|
63
|
+
patches: list[int] | None = None,
|
|
64
|
+
) -> list:
|
|
65
|
+
"""
|
|
66
|
+
Compute a set of features for a single label, including context features and patch features.
|
|
67
|
+
|
|
68
|
+
Parameters:
|
|
69
|
+
current_label (int): The label of the current region.
|
|
70
|
+
mask_plane (np.ndarray): The mask of all regions.
|
|
71
|
+
image_plane (np.ndarray): The intensity image.
|
|
72
|
+
all_features (list): The list of features to compute.
|
|
73
|
+
extra_properties (list): The list of extra properties to compute.
|
|
74
|
+
intensity_features (list): The list of intensity features to compute.
|
|
75
|
+
extra_intensity_features (list): The list of extra intensity features to compute.
|
|
76
|
+
num_closest (int): The number of closest regions to consider.
|
|
77
|
+
patches (list): The list of patch sizes to consider.
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
list: A list of features for the label.
|
|
81
|
+
"""
|
|
82
|
+
|
|
83
|
+
mask_of_current_label = (mask_plane == current_label).astype("uint8")
|
|
84
|
+
# check if image_plane has multiple channels
|
|
85
|
+
if len(image_plane.shape) == 3:
|
|
86
|
+
# compute all the features on the first channel and then intensity features on the other ones
|
|
87
|
+
feature_vector = worm_features.compute_base_label_features(
|
|
88
|
+
mask_of_current_label,
|
|
89
|
+
image_plane[0],
|
|
90
|
+
all_features,
|
|
91
|
+
extra_properties,
|
|
92
|
+
)
|
|
93
|
+
for i in range(1, image_plane.shape[0]):
|
|
94
|
+
other_channel_intensity_features = (
|
|
95
|
+
worm_features.compute_base_label_features(
|
|
96
|
+
mask_of_current_label,
|
|
97
|
+
image_plane[i],
|
|
98
|
+
intensity_features,
|
|
99
|
+
extra_intensity_features,
|
|
100
|
+
)
|
|
101
|
+
)
|
|
102
|
+
feature_vector += other_channel_intensity_features
|
|
103
|
+
else:
|
|
104
|
+
feature_vector = worm_features.compute_base_label_features(
|
|
105
|
+
mask_of_current_label, image_plane, all_features, extra_properties
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
if patches is not None:
|
|
109
|
+
for patch_size in patches:
|
|
110
|
+
if len(image_plane.shape) == 3:
|
|
111
|
+
patch_features = worm_features.compute_patch_features(
|
|
112
|
+
mask_of_current_label,
|
|
113
|
+
image_plane[0],
|
|
114
|
+
patch_size=patch_size,
|
|
115
|
+
)
|
|
116
|
+
for i in range(1, image_plane.shape[0]):
|
|
117
|
+
patch_features += worm_features.compute_patch_features(
|
|
118
|
+
mask_of_current_label,
|
|
119
|
+
image_plane[i],
|
|
120
|
+
patch_size=patch_size,
|
|
121
|
+
)
|
|
122
|
+
feature_vector += patch_features
|
|
123
|
+
else:
|
|
124
|
+
patch_features = worm_features.compute_patch_features(
|
|
125
|
+
mask_of_current_label, image_plane, patch_size=patch_size
|
|
126
|
+
)
|
|
127
|
+
feature_vector += patch_features
|
|
128
|
+
|
|
129
|
+
if num_closest is not None:
|
|
130
|
+
context = worm_features.get_context(
|
|
131
|
+
current_label,
|
|
132
|
+
mask_of_current_label,
|
|
133
|
+
mask_plane,
|
|
134
|
+
num_closest=num_closest,
|
|
135
|
+
)
|
|
136
|
+
if len(image_plane.shape) == 3:
|
|
137
|
+
context_features = worm_features.get_context_features(
|
|
138
|
+
context, image_plane[0], all_features, extra_properties
|
|
139
|
+
)
|
|
140
|
+
for i in range(1, image_plane.shape[0]):
|
|
141
|
+
context_features += worm_features.get_context_features(
|
|
142
|
+
context,
|
|
143
|
+
image_plane[i],
|
|
144
|
+
intensity_features,
|
|
145
|
+
extra_intensity_features,
|
|
146
|
+
)
|
|
147
|
+
feature_vector += context_features
|
|
148
|
+
else:
|
|
149
|
+
context_features = worm_features.get_context_features(
|
|
150
|
+
context, image_plane, all_features, extra_properties
|
|
151
|
+
)
|
|
152
|
+
feature_vector += context_features
|
|
153
|
+
|
|
154
|
+
return feature_vector
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def compute_features_of_plane(
|
|
158
|
+
mask_plane: np.ndarray,
|
|
159
|
+
image_plane: np.ndarray,
|
|
160
|
+
all_features: list[str],
|
|
161
|
+
extra_properties: list,
|
|
162
|
+
intensity_features: list[str],
|
|
163
|
+
extra_intensity_features: list,
|
|
164
|
+
num_closest: int | None = None,
|
|
165
|
+
patches: list[int] | None = None,
|
|
166
|
+
parallel: bool = True,
|
|
167
|
+
n_jobs: int = -1,
|
|
168
|
+
) -> list:
|
|
169
|
+
"""
|
|
170
|
+
Compute a set of features for a single label, including context features and patch features for all labels in a plane.
|
|
171
|
+
|
|
172
|
+
Parameters:
|
|
173
|
+
mask_plane (np.ndarray): The mask of all regions.
|
|
174
|
+
image_plane (np.ndarray): The intensity image.
|
|
175
|
+
all_features (list): The list of features to compute.
|
|
176
|
+
extra_properties (list): The list of extra properties to compute.
|
|
177
|
+
intensity_features (list): The list of intensity features to compute.
|
|
178
|
+
extra_intensity_features (list): The list of extra intensity features to compute.
|
|
179
|
+
num_closest (int): The number of closest regions to consider.
|
|
180
|
+
patches (list): The list of patch sizes to consider.
|
|
181
|
+
parallel (bool): Whether to compute features in parallel.
|
|
182
|
+
n_jobs (int): The number of jobs to run in parallel.
|
|
183
|
+
|
|
184
|
+
Returns:
|
|
185
|
+
list: A list of lists of features for all labels.
|
|
186
|
+
"""
|
|
187
|
+
|
|
188
|
+
if parallel:
|
|
189
|
+
features_of_all_labels = Parallel(n_jobs=n_jobs)(
|
|
190
|
+
delayed(compute_features_of_label)(
|
|
191
|
+
current_label,
|
|
192
|
+
mask_plane,
|
|
193
|
+
image_plane,
|
|
194
|
+
all_features,
|
|
195
|
+
extra_properties,
|
|
196
|
+
intensity_features,
|
|
197
|
+
extra_intensity_features,
|
|
198
|
+
num_closest=num_closest,
|
|
199
|
+
patches=patches,
|
|
200
|
+
)
|
|
201
|
+
for current_label in np.unique(mask_plane)[1:]
|
|
202
|
+
)
|
|
203
|
+
else:
|
|
204
|
+
features_of_all_labels = [
|
|
205
|
+
compute_features_of_label(
|
|
206
|
+
current_label,
|
|
207
|
+
mask_plane,
|
|
208
|
+
image_plane,
|
|
209
|
+
all_features,
|
|
210
|
+
extra_properties,
|
|
211
|
+
intensity_features,
|
|
212
|
+
extra_intensity_features,
|
|
213
|
+
num_closest=num_closest,
|
|
214
|
+
patches=patches,
|
|
215
|
+
)
|
|
216
|
+
for current_label in np.unique(mask_plane)[1:]
|
|
217
|
+
]
|
|
218
|
+
return features_of_all_labels
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def classify_plane(
|
|
222
|
+
mask_plane: np.ndarray,
|
|
223
|
+
image_plane: np.ndarray,
|
|
224
|
+
classifier: xgboost.XGBClassifier,
|
|
225
|
+
all_features: list[str],
|
|
226
|
+
extra_properties: list,
|
|
227
|
+
intensity_features: list[str],
|
|
228
|
+
extra_intensity_features: list,
|
|
229
|
+
num_closest: int | None = None,
|
|
230
|
+
patches: list[int] | None = None,
|
|
231
|
+
parallel: bool = True,
|
|
232
|
+
n_jobs: int = -1,
|
|
233
|
+
confidence_threshold: float | None = None,
|
|
234
|
+
) -> np.ndarray | None:
|
|
235
|
+
"""
|
|
236
|
+
Compute the features of all the labels in a plane and classify them using an XGBoost classifier.
|
|
237
|
+
|
|
238
|
+
Parameters:
|
|
239
|
+
mask_plane (np.ndarray): The mask of all regions.
|
|
240
|
+
image_plane (np.ndarray): The intensity image.
|
|
241
|
+
classifier (xgboost.XGBClassifier): The trained classifier object.
|
|
242
|
+
all_features (list): The list of features to compute.
|
|
243
|
+
extra_properties (list): The list of extra properties to compute.
|
|
244
|
+
intensity_features (list): The list of intensity features to compute.
|
|
245
|
+
extra_intensity_features (list): The list of extra intensity features to compute.
|
|
246
|
+
num_closest (int): The number of closest regions to consider.
|
|
247
|
+
patches (list): The list of patch sizes to consider.
|
|
248
|
+
parallel (bool): Whether to compute features in parallel.
|
|
249
|
+
n_jobs (int): The number of jobs to run in parallel.
|
|
250
|
+
confidence_threshold (float): The confidence threshold for predictions to be considered valid.
|
|
251
|
+
|
|
252
|
+
Returns:
|
|
253
|
+
list: A list of predicted classes for all labels in the plane.
|
|
254
|
+
"""
|
|
255
|
+
|
|
256
|
+
features = compute_features_of_plane(
|
|
257
|
+
mask_plane,
|
|
258
|
+
image_plane,
|
|
259
|
+
all_features,
|
|
260
|
+
extra_properties,
|
|
261
|
+
intensity_features,
|
|
262
|
+
extra_intensity_features,
|
|
263
|
+
num_closest=num_closest,
|
|
264
|
+
patches=patches,
|
|
265
|
+
parallel=parallel,
|
|
266
|
+
n_jobs=n_jobs,
|
|
267
|
+
)
|
|
268
|
+
if len(features) == 0:
|
|
269
|
+
return None
|
|
270
|
+
predictions = classifier.predict_proba(features)
|
|
271
|
+
predicted_classes = np.argmax(predictions, axis=1)
|
|
272
|
+
if confidence_threshold is not None:
|
|
273
|
+
for i in range(len(predicted_classes)):
|
|
274
|
+
if np.max(predictions[i]) < confidence_threshold:
|
|
275
|
+
predicted_classes[i] = -1
|
|
276
|
+
return predicted_classes
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
def classify_labels(
|
|
280
|
+
mask: np.ndarray,
|
|
281
|
+
image: np.ndarray,
|
|
282
|
+
classifier: xgboost.XGBClassifier,
|
|
283
|
+
all_features: list[str],
|
|
284
|
+
extra_properties: list,
|
|
285
|
+
intensity_features: list[str],
|
|
286
|
+
extra_intensity_features: list,
|
|
287
|
+
num_closest: int | None = None,
|
|
288
|
+
patches: list[int] | None = None,
|
|
289
|
+
parallel: bool = True,
|
|
290
|
+
n_jobs: int = -1,
|
|
291
|
+
is_zstack: bool = False,
|
|
292
|
+
confidence_threshold: float | None = None,
|
|
293
|
+
) -> list:
|
|
294
|
+
"""
|
|
295
|
+
Compute the features of all the labels in a mask and classify them using an XGBoost classifier.
|
|
296
|
+
|
|
297
|
+
Parameters:
|
|
298
|
+
mask (np.ndarray): The mask of all regions.
|
|
299
|
+
image (np.ndarray): The intensity image.
|
|
300
|
+
classifier (xgboost.XGBClassifier): The trained classifier object.
|
|
301
|
+
all_features (list): The list of features to compute.
|
|
302
|
+
extra_properties (list): The list of extra properties to compute.
|
|
303
|
+
intensity_features (list): The list of intensity features to compute.
|
|
304
|
+
extra_intensity_features (list): The list of extra intensity features to compute.
|
|
305
|
+
num_closest (int): The number of closest regions to consider.
|
|
306
|
+
patches (list): The list of patch sizes to consider.
|
|
307
|
+
parallel (bool): Whether to compute features in parallel.
|
|
308
|
+
n_jobs (int): The number of jobs to run in parallel.
|
|
309
|
+
is_zstack (bool): Whether the image is a z-stack.
|
|
310
|
+
confidence_threshold (float): The confidence threshold for predictions to be considered valid.
|
|
311
|
+
|
|
312
|
+
Returns:
|
|
313
|
+
list: A list of predicted classes for all labels in the mask.
|
|
314
|
+
"""
|
|
315
|
+
|
|
316
|
+
if is_zstack or len(image.shape) > 3:
|
|
317
|
+
assert (
|
|
318
|
+
mask.shape[0] == image.shape[0]
|
|
319
|
+
), "The number of planes in the mask and the image should be the same."
|
|
320
|
+
return [
|
|
321
|
+
classify_plane(
|
|
322
|
+
mask_plane,
|
|
323
|
+
image_plane,
|
|
324
|
+
classifier,
|
|
325
|
+
all_features,
|
|
326
|
+
extra_properties,
|
|
327
|
+
intensity_features,
|
|
328
|
+
extra_intensity_features,
|
|
329
|
+
num_closest=num_closest,
|
|
330
|
+
patches=patches,
|
|
331
|
+
parallel=parallel,
|
|
332
|
+
n_jobs=n_jobs,
|
|
333
|
+
confidence_threshold=confidence_threshold,
|
|
334
|
+
)
|
|
335
|
+
for mask_plane, image_plane in zip(mask, image)
|
|
336
|
+
]
|
|
337
|
+
else:
|
|
338
|
+
return classify_plane(
|
|
339
|
+
mask,
|
|
340
|
+
image,
|
|
341
|
+
classifier,
|
|
342
|
+
all_features,
|
|
343
|
+
extra_properties,
|
|
344
|
+
intensity_features,
|
|
345
|
+
extra_intensity_features,
|
|
346
|
+
num_closest=num_closest,
|
|
347
|
+
patches=patches,
|
|
348
|
+
parallel=parallel,
|
|
349
|
+
n_jobs=n_jobs,
|
|
350
|
+
confidence_threshold=confidence_threshold,
|
|
351
|
+
)
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
def classify_labels_features_dict(
|
|
355
|
+
mask: np.ndarray,
|
|
356
|
+
image: np.ndarray,
|
|
357
|
+
clf: xgboost.XGBClassifier,
|
|
358
|
+
features_dict: dict,
|
|
359
|
+
parallel: bool = True,
|
|
360
|
+
n_jobs: int = -1,
|
|
361
|
+
is_zstack: bool = False,
|
|
362
|
+
confidence_threshold: float | None = None,
|
|
363
|
+
) -> list:
|
|
364
|
+
"""
|
|
365
|
+
Classify all labels in a mask using a features dictionary.
|
|
366
|
+
|
|
367
|
+
Convenience wrapper around :func:`classify_labels` that unpacks feature
|
|
368
|
+
configuration from a dictionary rather than requiring individual arguments.
|
|
369
|
+
|
|
370
|
+
Parameters:
|
|
371
|
+
mask (np.ndarray): Labeled mask of all regions.
|
|
372
|
+
image (np.ndarray): Intensity image.
|
|
373
|
+
clf (xgboost.XGBClassifier): Trained XGBoost classifier.
|
|
374
|
+
features_dict (dict): Dictionary with keys ``"all_features"``,
|
|
375
|
+
``"extra_properties"``, ``"intensity_features"``,
|
|
376
|
+
``"extra_intensity_features"``, ``"num_closest"``, and ``"patches"``.
|
|
377
|
+
parallel (bool, optional): Whether to compute features in parallel.
|
|
378
|
+
(default: True)
|
|
379
|
+
n_jobs (int, optional): Number of parallel jobs (passed to joblib).
|
|
380
|
+
(default: -1)
|
|
381
|
+
is_zstack (bool, optional): Whether the image is a z-stack. (default: False)
|
|
382
|
+
confidence_threshold (float, optional): Minimum prediction confidence;
|
|
383
|
+
predictions below this threshold are set to -1. (default: None)
|
|
384
|
+
|
|
385
|
+
Returns:
|
|
386
|
+
list: Predicted class indices for all labels, structured as returned by
|
|
387
|
+
:func:`classify_labels`.
|
|
388
|
+
"""
|
|
389
|
+
return classify_labels(
|
|
390
|
+
mask,
|
|
391
|
+
image,
|
|
392
|
+
clf,
|
|
393
|
+
features_dict["all_features"],
|
|
394
|
+
features_dict["extra_properties"],
|
|
395
|
+
features_dict["intensity_features"],
|
|
396
|
+
features_dict["extra_intensity_features"],
|
|
397
|
+
num_closest=features_dict["num_closest"],
|
|
398
|
+
patches=features_dict["patches"],
|
|
399
|
+
parallel=parallel,
|
|
400
|
+
n_jobs=n_jobs,
|
|
401
|
+
is_zstack=is_zstack,
|
|
402
|
+
confidence_threshold=confidence_threshold,
|
|
403
|
+
)
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
def convert_classification_to_mask(
|
|
407
|
+
mask: np.ndarray,
|
|
408
|
+
classification: list,
|
|
409
|
+
is_zstack: bool = False,
|
|
410
|
+
) -> np.ndarray:
|
|
411
|
+
"""
|
|
412
|
+
Convert a classification (list of predicted classes) to a mask.
|
|
413
|
+
|
|
414
|
+
Parameters:
|
|
415
|
+
mask (np.ndarray): The mask of all regions.
|
|
416
|
+
classification (list): The list of predicted classes for all labels.
|
|
417
|
+
is_zstack (bool): Whether the image is a z-stack.
|
|
418
|
+
|
|
419
|
+
Returns:
|
|
420
|
+
np.ndarray: The given mask with pixel values replaced with class number + 1.
|
|
421
|
+
"""
|
|
422
|
+
|
|
423
|
+
new_mask = np.zeros_like(mask)
|
|
424
|
+
|
|
425
|
+
if is_zstack or len(mask.shape) > 2:
|
|
426
|
+
for i, plane_classification in enumerate(classification):
|
|
427
|
+
if plane_classification is not None:
|
|
428
|
+
for j, label in enumerate(np.unique(mask[i])[1:]):
|
|
429
|
+
new_mask[i][mask[i] == label] = plane_classification[j] + 1
|
|
430
|
+
else:
|
|
431
|
+
if classification is not None:
|
|
432
|
+
for i, label in enumerate(np.unique(mask)[1:]):
|
|
433
|
+
new_mask[mask == label] = classification[i] + 1
|
|
434
|
+
|
|
435
|
+
return new_mask
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
def convert_classification_to_dataframe(
|
|
439
|
+
mask: np.ndarray,
|
|
440
|
+
classification: list,
|
|
441
|
+
is_zstack: bool = False,
|
|
442
|
+
) -> pd.DataFrame:
|
|
443
|
+
"""
|
|
444
|
+
Convert a classification (list of predicted classes) to a pandas DataFrame.
|
|
445
|
+
|
|
446
|
+
Parameters:
|
|
447
|
+
mask (np.ndarray): The mask of all regions.
|
|
448
|
+
classification (list): The list of predicted classes for all labels.
|
|
449
|
+
is_zstack (bool): Whether the image is a z-stack.
|
|
450
|
+
|
|
451
|
+
Returns:
|
|
452
|
+
pd.DataFrame: A DataFrame with columns "Plane", "Label", and "Class".
|
|
453
|
+
"""
|
|
454
|
+
|
|
455
|
+
data = []
|
|
456
|
+
if is_zstack or len(mask.shape) > 2:
|
|
457
|
+
for i, plane_classification in enumerate(classification):
|
|
458
|
+
if plane_classification is not None:
|
|
459
|
+
for j, label in enumerate(np.unique(mask[i])[1:]):
|
|
460
|
+
data.append(
|
|
461
|
+
{
|
|
462
|
+
"Plane": i,
|
|
463
|
+
"Label": int(label),
|
|
464
|
+
"Class": plane_classification[j],
|
|
465
|
+
}
|
|
466
|
+
)
|
|
467
|
+
else:
|
|
468
|
+
if classification is not None:
|
|
469
|
+
for i, label in enumerate(np.unique(mask)[1:]):
|
|
470
|
+
data.append(
|
|
471
|
+
{
|
|
472
|
+
"Plane": 0,
|
|
473
|
+
"Label": int(label),
|
|
474
|
+
"Class": classification[i],
|
|
475
|
+
}
|
|
476
|
+
)
|
|
477
|
+
return pd.DataFrame(data)
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
def classify_labels_and_convert_to_mask(
|
|
481
|
+
mask: np.ndarray,
|
|
482
|
+
image: np.ndarray,
|
|
483
|
+
classifier: xgboost.XGBClassifier,
|
|
484
|
+
all_features: list[str],
|
|
485
|
+
extra_properties: list,
|
|
486
|
+
intensity_features: list[str],
|
|
487
|
+
extra_intensity_features: list,
|
|
488
|
+
num_closest: int | None = None,
|
|
489
|
+
patches: list[int] | None = None,
|
|
490
|
+
parallel: bool = True,
|
|
491
|
+
n_jobs: int = -1,
|
|
492
|
+
is_zstack: bool = False,
|
|
493
|
+
confidence_threshold: float | None = None,
|
|
494
|
+
) -> np.ndarray:
|
|
495
|
+
"""
|
|
496
|
+
Classify all the labels in a mask using an XGBoost classifier and convert the classification to a mask.
|
|
497
|
+
|
|
498
|
+
Parameters:
|
|
499
|
+
mask (np.ndarray): The mask of all regions.
|
|
500
|
+
image (np.ndarray): The intensity image.
|
|
501
|
+
classifier (xgboost.XGBClassifier): The trained classifier object.
|
|
502
|
+
all_features (list): The list of features to compute.
|
|
503
|
+
extra_properties (list): The list of extra properties to compute.
|
|
504
|
+
intensity_features (list): The list of intensity features to compute.
|
|
505
|
+
extra_intensity_features (list): The list of extra intensity features to compute.
|
|
506
|
+
num_closest (int): The number of closest regions to consider.
|
|
507
|
+
patches (list): The list of patch sizes to consider.
|
|
508
|
+
parallel (bool): Whether to compute features in parallel.
|
|
509
|
+
n_jobs (int): The number of jobs to run in parallel.
|
|
510
|
+
is_zstack (bool): Whether the image is a z-stack.
|
|
511
|
+
confidence_threshold (float): The confidence threshold for predictions to be considered valid.
|
|
512
|
+
|
|
513
|
+
Returns:
|
|
514
|
+
np.ndarray: The given mask with pixel values replaced with class number + 1.
|
|
515
|
+
"""
|
|
516
|
+
|
|
517
|
+
classification = classify_labels(
|
|
518
|
+
mask,
|
|
519
|
+
image,
|
|
520
|
+
classifier,
|
|
521
|
+
all_features,
|
|
522
|
+
extra_properties,
|
|
523
|
+
intensity_features,
|
|
524
|
+
extra_intensity_features,
|
|
525
|
+
num_closest=num_closest,
|
|
526
|
+
patches=patches,
|
|
527
|
+
parallel=parallel,
|
|
528
|
+
n_jobs=n_jobs,
|
|
529
|
+
is_zstack=is_zstack,
|
|
530
|
+
confidence_threshold=confidence_threshold,
|
|
531
|
+
)
|
|
532
|
+
return convert_classification_to_mask(mask, classification)
|
|
533
|
+
|
|
534
|
+
|
|
535
|
+
def classify_labels_and_convert_to_dataframe(
|
|
536
|
+
mask: np.ndarray,
|
|
537
|
+
image: np.ndarray,
|
|
538
|
+
classifier: xgboost.XGBClassifier,
|
|
539
|
+
all_features: list[str],
|
|
540
|
+
extra_properties: list,
|
|
541
|
+
intensity_features: list[str],
|
|
542
|
+
extra_intensity_features: list,
|
|
543
|
+
num_closest: int | None = None,
|
|
544
|
+
patches: list[int] | None = None,
|
|
545
|
+
parallel: bool = True,
|
|
546
|
+
n_jobs: int = -1,
|
|
547
|
+
is_zstack: bool = False,
|
|
548
|
+
confidence_threshold: float | None = None,
|
|
549
|
+
) -> pd.DataFrame:
|
|
550
|
+
"""
|
|
551
|
+
Classify all the labels in a mask using an XGBoost classifier and convert the classification to a pandas DataFrame.
|
|
552
|
+
|
|
553
|
+
Parameters:
|
|
554
|
+
mask (np.ndarray): The mask of all regions.
|
|
555
|
+
image (np.ndarray): The intensity image.
|
|
556
|
+
classifier (xgboost.XGBClassifier): The trained classifier object.
|
|
557
|
+
all_features (list): The list of features to compute.
|
|
558
|
+
extra_properties (list): The list of extra properties to compute.
|
|
559
|
+
intensity_features (list): The list of intensity features to compute.
|
|
560
|
+
extra_intensity_features (list): The list of extra intensity features to compute.
|
|
561
|
+
num_closest (int): The number of closest regions to consider.
|
|
562
|
+
patches (list): The list of patch sizes to consider.
|
|
563
|
+
parallel (bool): Whether to compute features in parallel.
|
|
564
|
+
n_jobs (int): The number of jobs to run in parallel.
|
|
565
|
+
is_zstack (bool): Whether the image is a z-stack.
|
|
566
|
+
confidence_threshold (float): The confidence threshold for predictions to be considered valid.
|
|
567
|
+
|
|
568
|
+
Returns:
|
|
569
|
+
pd.DataFrame: A DataFrame with columns "Plane", "Label", and "Class".
|
|
570
|
+
"""
|
|
571
|
+
|
|
572
|
+
classification = classify_labels(
|
|
573
|
+
mask,
|
|
574
|
+
image,
|
|
575
|
+
classifier,
|
|
576
|
+
all_features,
|
|
577
|
+
extra_properties,
|
|
578
|
+
intensity_features,
|
|
579
|
+
extra_intensity_features,
|
|
580
|
+
num_closest=num_closest,
|
|
581
|
+
patches=patches,
|
|
582
|
+
parallel=parallel,
|
|
583
|
+
n_jobs=n_jobs,
|
|
584
|
+
is_zstack=is_zstack,
|
|
585
|
+
confidence_threshold=confidence_threshold,
|
|
586
|
+
)
|
|
587
|
+
return convert_classification_to_dataframe(mask, classification)
|
|
588
|
+
|
|
589
|
+
|
|
590
|
+
def classify_labels_and_convert_to_mask_features_dict(
|
|
591
|
+
mask: np.ndarray,
|
|
592
|
+
image: np.ndarray,
|
|
593
|
+
clf: xgboost.XGBClassifier,
|
|
594
|
+
features_dict: dict,
|
|
595
|
+
parallel: bool = True,
|
|
596
|
+
n_jobs: int = -1,
|
|
597
|
+
is_zstack: bool = False,
|
|
598
|
+
confidence_threshold: float | None = None,
|
|
599
|
+
) -> np.ndarray:
|
|
600
|
+
"""
|
|
601
|
+
Classify all labels using a features dictionary and return the result as a mask.
|
|
602
|
+
|
|
603
|
+
Combines :func:`classify_labels_features_dict` and
|
|
604
|
+
:func:`convert_classification_to_mask`.
|
|
605
|
+
|
|
606
|
+
Parameters:
|
|
607
|
+
mask (np.ndarray): Labeled mask of all regions.
|
|
608
|
+
image (np.ndarray): Intensity image.
|
|
609
|
+
clf (xgboost.XGBClassifier): Trained XGBoost classifier.
|
|
610
|
+
features_dict (dict): Feature configuration dictionary (see
|
|
611
|
+
:func:`classify_labels_features_dict`).
|
|
612
|
+
parallel (bool, optional): Whether to compute features in parallel.
|
|
613
|
+
(default: True)
|
|
614
|
+
n_jobs (int, optional): Number of parallel jobs. (default: -1)
|
|
615
|
+
is_zstack (bool, optional): Whether the image is a z-stack. (default: False)
|
|
616
|
+
confidence_threshold (float, optional): Minimum prediction confidence.
|
|
617
|
+
(default: None)
|
|
618
|
+
|
|
619
|
+
Returns:
|
|
620
|
+
np.ndarray: Mask with pixel values replaced by predicted class index + 1.
|
|
621
|
+
"""
|
|
622
|
+
classification = classify_labels_features_dict(
|
|
623
|
+
mask,
|
|
624
|
+
image,
|
|
625
|
+
clf,
|
|
626
|
+
features_dict,
|
|
627
|
+
parallel=parallel,
|
|
628
|
+
n_jobs=n_jobs,
|
|
629
|
+
is_zstack=is_zstack,
|
|
630
|
+
confidence_threshold=confidence_threshold,
|
|
631
|
+
)
|
|
632
|
+
return convert_classification_to_mask(mask, classification, is_zstack=is_zstack)
|
|
633
|
+
|
|
634
|
+
|
|
635
|
+
def classify_labels_and_convert_to_dataframe_features_dict(
|
|
636
|
+
mask: np.ndarray,
|
|
637
|
+
image: np.ndarray,
|
|
638
|
+
clf: xgboost.XGBClassifier,
|
|
639
|
+
features_dict: dict,
|
|
640
|
+
parallel: bool = True,
|
|
641
|
+
n_jobs: int = -1,
|
|
642
|
+
is_zstack: bool = False,
|
|
643
|
+
confidence_threshold: float | None = None,
|
|
644
|
+
) -> pd.DataFrame:
|
|
645
|
+
"""
|
|
646
|
+
Classify all labels using a features dictionary and return the result as a DataFrame.
|
|
647
|
+
|
|
648
|
+
Combines :func:`classify_labels_features_dict` and
|
|
649
|
+
:func:`convert_classification_to_dataframe`.
|
|
650
|
+
|
|
651
|
+
Parameters:
|
|
652
|
+
mask (np.ndarray): Labeled mask of all regions.
|
|
653
|
+
image (np.ndarray): Intensity image.
|
|
654
|
+
clf (xgboost.XGBClassifier): Trained XGBoost classifier.
|
|
655
|
+
features_dict (dict): Feature configuration dictionary (see
|
|
656
|
+
:func:`classify_labels_features_dict`).
|
|
657
|
+
parallel (bool, optional): Whether to compute features in parallel.
|
|
658
|
+
(default: True)
|
|
659
|
+
n_jobs (int, optional): Number of parallel jobs. (default: -1)
|
|
660
|
+
is_zstack (bool, optional): Whether the image is a z-stack. (default: False)
|
|
661
|
+
confidence_threshold (float, optional): Minimum prediction confidence.
|
|
662
|
+
(default: None)
|
|
663
|
+
|
|
664
|
+
Returns:
|
|
665
|
+
pd.DataFrame: DataFrame with columns ``"Plane"``, ``"Label"``, and ``"Class"``.
|
|
666
|
+
"""
|
|
667
|
+
classification = classify_labels_features_dict(
|
|
668
|
+
mask,
|
|
669
|
+
image,
|
|
670
|
+
clf,
|
|
671
|
+
features_dict,
|
|
672
|
+
parallel=parallel,
|
|
673
|
+
n_jobs=n_jobs,
|
|
674
|
+
is_zstack=is_zstack,
|
|
675
|
+
confidence_threshold=confidence_threshold,
|
|
676
|
+
)
|
|
677
|
+
return convert_classification_to_dataframe(
|
|
678
|
+
mask, classification, is_zstack=is_zstack
|
|
679
|
+
)
|