byotrack 1.2.0.dev1__tar.gz → 1.2.0.dev3__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.
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/PKG-INFO +1 -1
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/__init__.py +1 -1
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/api/detector/detections.py +46 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/api/features_extractor.py +40 -1
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/dataset/ctc.py +41 -4
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/fiji/run.py +14 -3
- byotrack-1.2.0.dev3/byotrack/implementation/linker/frame_by_frame/base.py +794 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/implementation/linker/frame_by_frame/kalman_linker.py +24 -13
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/implementation/linker/frame_by_frame/koft.py +32 -21
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/implementation/linker/frame_by_frame/nearest_neighbor.py +24 -12
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/implementation/linker/trackmate/trackmate.py +1 -2
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/metrics/ctc.py +152 -14
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack.egg-info/PKG-INFO +1 -1
- byotrack-1.2.0.dev1/byotrack/implementation/linker/frame_by_frame/base.py +0 -486
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/LICENSE +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/README.md +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/api/__init__.py +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/api/detector/__init__.py +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/api/detector/detector.py +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/api/linker.py +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/api/optical_flow/__init__.py +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/api/optical_flow/optical_flow.py +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/api/parameters.py +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/api/refiner.py +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/api/tracker.py +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/api/tracks.py +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/dataset/__init__.py +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/example_data.py +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/fiji/__init__.py +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/fiji/io.py +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/icy/__init__.py +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/icy/io.py +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/icy/run.py +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/implementation/__init__.py +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/implementation/detector/__init__.py +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/implementation/detector/stardist.py +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/implementation/detector/wavelet.py +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/implementation/linker/__init__.py +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/implementation/linker/frame_by_frame/__init__.py +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/implementation/linker/frame_by_frame/greedy_lap.py +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/implementation/linker/icy_emht/__init__.py +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/implementation/linker/icy_emht/emht_protocol.xml +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/implementation/linker/icy_emht/emht_protocol_with_full_specs.xml +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/implementation/linker/icy_emht/icy_emht.py +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/implementation/linker/trackmate/__init__.py +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/implementation/linker/trackmate/_trackmate.py +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/implementation/optical_flow/__init__.py +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/implementation/optical_flow/opencv.py +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/implementation/optical_flow/skimage.py +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/implementation/refiner/__init__.py +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/implementation/refiner/cleaner.py +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/implementation/refiner/interpolater.py +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/implementation/refiner/propagation.py +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/implementation/refiner/stitching/__init__.py +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/implementation/refiner/stitching/dist_stitcher.py +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/implementation/refiner/stitching/emc2.py +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/metrics/__init__.py +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/py.typed +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/utils.py +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/video/__init__.py +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/video/reader.py +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/video/transforms.py +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/video/video.py +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack/visualize.py +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack.egg-info/SOURCES.txt +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack.egg-info/dependency_links.txt +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack.egg-info/requires.txt +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/byotrack.egg-info/top_level.txt +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/pyproject.toml +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/setup.cfg +0 -0
- {byotrack-1.2.0.dev1 → byotrack-1.2.0.dev3}/setup.py +0 -0
|
@@ -36,6 +36,32 @@ def _check_confidence(confidence: torch.Tensor) -> None:
|
|
|
36
36
|
assert confidence.dtype is torch.float32
|
|
37
37
|
|
|
38
38
|
|
|
39
|
+
@numba.njit
|
|
40
|
+
def _compute_mass(segmentation: np.ndarray) -> np.ndarray:
|
|
41
|
+
"""Extract the number of pixels of each object in the segmentation
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
segmentation (np.ndarray): Segmentation mask
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
np.ndarray: Mass for each object
|
|
48
|
+
Shape (n,), dtype: int32
|
|
49
|
+
|
|
50
|
+
"""
|
|
51
|
+
n = segmentation.max()
|
|
52
|
+
mass = np.zeros(n, dtype=np.int32)
|
|
53
|
+
|
|
54
|
+
# Ravel in 1D
|
|
55
|
+
segmentation = segmentation.reshape(-1)
|
|
56
|
+
|
|
57
|
+
for i in range(segmentation.shape[0]):
|
|
58
|
+
instance = segmentation[i] - 1
|
|
59
|
+
if instance != -1:
|
|
60
|
+
mass[instance] += 1
|
|
61
|
+
|
|
62
|
+
return mass
|
|
63
|
+
|
|
64
|
+
|
|
39
65
|
@numba.njit(parallel=False)
|
|
40
66
|
def _position_from_segmentation(segmentation: np.ndarray) -> np.ndarray:
|
|
41
67
|
"""Return the center (mean) of each instance in the segmentation"""
|
|
@@ -278,6 +304,8 @@ class Detections:
|
|
|
278
304
|
Shape: ([D, ]H, W), dtype: int32
|
|
279
305
|
confidence (torch.Tensor): Confidence for each instance
|
|
280
306
|
Shape: (N,), dtype: float32
|
|
307
|
+
mass (torch.Tensor): Size of each object in pixel, inferred from the data.
|
|
308
|
+
Shape: (N,), dtype: int32
|
|
281
309
|
use_median_position (bool): Use median instead of mean to compute positions from segmentation.
|
|
282
310
|
Default: True (Usually more robust)
|
|
283
311
|
|
|
@@ -360,6 +388,15 @@ class Detections:
|
|
|
360
388
|
|
|
361
389
|
return confidence
|
|
362
390
|
|
|
391
|
+
@property
|
|
392
|
+
def mass(self) -> torch.Tensor:
|
|
393
|
+
mass = self.data.get("mass", self._lazy_extrapolated_data.get("mass"))
|
|
394
|
+
if mass is None:
|
|
395
|
+
mass = self._extrapolate_mass()
|
|
396
|
+
self._lazy_extrapolated_data["confidence"] = mass
|
|
397
|
+
|
|
398
|
+
return mass
|
|
399
|
+
|
|
363
400
|
@property
|
|
364
401
|
def use_median_position(self) -> bool:
|
|
365
402
|
return self._use_median_position
|
|
@@ -443,6 +480,15 @@ class Detections:
|
|
|
443
480
|
"""Extrapolate confidence"""
|
|
444
481
|
return torch.ones(self.length)
|
|
445
482
|
|
|
483
|
+
def _extrapolate_mass(self) -> torch.Tensor:
|
|
484
|
+
if "segmentation" in self.data:
|
|
485
|
+
return torch.tensor(_compute_mass(self.data["segmentation"].numpy()), dtype=torch.int32)
|
|
486
|
+
|
|
487
|
+
if "bbox" in self.data:
|
|
488
|
+
return self.data["bbox"][:, self.dim :].prod(dim=-1)
|
|
489
|
+
|
|
490
|
+
return torch.ones(self.length, dtype=torch.int32)
|
|
491
|
+
|
|
446
492
|
def __len__(self) -> int:
|
|
447
493
|
return self.length
|
|
448
494
|
|
|
@@ -4,6 +4,7 @@ from abc import ABC, abstractmethod
|
|
|
4
4
|
from typing import Iterable
|
|
5
5
|
|
|
6
6
|
import numpy as np
|
|
7
|
+
import numba # type: ignore
|
|
7
8
|
import torch
|
|
8
9
|
|
|
9
10
|
import byotrack # pylint: disable=cyclic-import
|
|
@@ -56,4 +57,42 @@ class MultiFeaturesExtractor(FeaturesExtractor):
|
|
|
56
57
|
return torch.cat(features, dim=-1)
|
|
57
58
|
|
|
58
59
|
|
|
59
|
-
|
|
60
|
+
class MassExtractor(FeaturesExtractor):
|
|
61
|
+
"""Extract the mass of each detection (number of pixels)"""
|
|
62
|
+
|
|
63
|
+
def __call__(self, frame: np.ndarray, detections: byotrack.Detections):
|
|
64
|
+
return detections.mass
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class IntensityExtractor(FeaturesExtractor):
|
|
68
|
+
"""Extract the sum of intensities of each detection"""
|
|
69
|
+
|
|
70
|
+
def __call__(self, frame: np.ndarray, detections: byotrack.Detections):
|
|
71
|
+
torch.tensor(compute_intensity(detections.segmentation.numpy(), frame.sum(axis=-1)), dtype=torch.float32)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@numba.njit
|
|
75
|
+
def compute_intensity(segmentation: np.ndarray, frame: np.ndarray) -> np.ndarray:
|
|
76
|
+
"""Extract the cumulated intensity of each detection
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
segmentation (np.ndarray): Segmentation mask
|
|
80
|
+
frame (np.ndarray): Video frame (should have the same number of pixels than segmentation)
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
np.ndarray: Sum of intensity for each object
|
|
84
|
+
|
|
85
|
+
"""
|
|
86
|
+
n = segmentation.max()
|
|
87
|
+
intensity = np.zeros(n, dtype=frame.dtype)
|
|
88
|
+
|
|
89
|
+
# Ravel in 1D
|
|
90
|
+
segmentation = segmentation.reshape(-1)
|
|
91
|
+
frame = frame.reshape(-1)
|
|
92
|
+
|
|
93
|
+
for i in range(segmentation.shape[0]):
|
|
94
|
+
instance = segmentation[i] - 1
|
|
95
|
+
if instance != -1:
|
|
96
|
+
intensity[instance] += frame[i]
|
|
97
|
+
|
|
98
|
+
return intensity
|
|
@@ -286,6 +286,8 @@ def _fast_disk_2d(
|
|
|
286
286
|
positions: np.ndarray,
|
|
287
287
|
identifiers: np.ndarray,
|
|
288
288
|
radius: np.ndarray,
|
|
289
|
+
*,
|
|
290
|
+
overwrite=False,
|
|
289
291
|
):
|
|
290
292
|
"""Fast inplace drawing of disk in 2D
|
|
291
293
|
|
|
@@ -300,6 +302,8 @@ def _fast_disk_2d(
|
|
|
300
302
|
Shape: (n,), dtype: uint16
|
|
301
303
|
radius (np.ndarray): Radius of each disk
|
|
302
304
|
Shape: (n, ), dtype: float32
|
|
305
|
+
overwrite (bool): Overwrite pixels that are already written (!=0)
|
|
306
|
+
Default: False
|
|
303
307
|
|
|
304
308
|
"""
|
|
305
309
|
positions_round = np.round(positions).astype(np.int64)
|
|
@@ -315,6 +319,9 @@ def _fast_disk_2d(
|
|
|
315
319
|
if not 0 <= i < segmentation.shape[0] or not 0 <= j < segmentation.shape[1]:
|
|
316
320
|
continue
|
|
317
321
|
|
|
322
|
+
if not overwrite and segmentation[i, j] != 0 and best_dist[i, j] == np.inf:
|
|
323
|
+
continue
|
|
324
|
+
|
|
318
325
|
delta = pos - positions[k]
|
|
319
326
|
dist = delta @ delta
|
|
320
327
|
|
|
@@ -325,12 +332,15 @@ def _fast_disk_2d(
|
|
|
325
332
|
|
|
326
333
|
|
|
327
334
|
@numba.njit(parallel=True)
|
|
328
|
-
def _fast_disk_3d(
|
|
335
|
+
def _fast_disk_3d( # pylint: disable=too-many-locals
|
|
329
336
|
segmentation: np.ndarray,
|
|
330
337
|
bbox: np.ndarray,
|
|
331
338
|
positions: np.ndarray,
|
|
332
339
|
identifiers: np.ndarray,
|
|
333
340
|
radius: np.ndarray,
|
|
341
|
+
*,
|
|
342
|
+
anisoptropy=1.0,
|
|
343
|
+
overwrite=False,
|
|
334
344
|
):
|
|
335
345
|
"""Fast inplace drawing of disk in 3D
|
|
336
346
|
|
|
@@ -345,6 +355,11 @@ def _fast_disk_3d(
|
|
|
345
355
|
Shape: (n,), dtype: uint16
|
|
346
356
|
radius (np.ndarray): Radius of each disk
|
|
347
357
|
Shape: (n, ), dtype: float32
|
|
358
|
+
anisotropy (float): Relative size of a pixel along the depth dimension
|
|
359
|
+
versus height/width dimensions.
|
|
360
|
+
Default: 1.0
|
|
361
|
+
overwrite (bool): Overwrite pixels that are already written (!=0)
|
|
362
|
+
Default: False
|
|
348
363
|
|
|
349
364
|
"""
|
|
350
365
|
positions_round = np.round(positions).astype(np.int64)
|
|
@@ -364,7 +379,11 @@ def _fast_disk_3d(
|
|
|
364
379
|
):
|
|
365
380
|
continue
|
|
366
381
|
|
|
382
|
+
if not overwrite and segmentation[z, i, j] != 0 and best_dist[z, i, j] == np.inf:
|
|
383
|
+
continue
|
|
384
|
+
|
|
367
385
|
delta = pos - positions[k]
|
|
386
|
+
delta[0] *= anisoptropy # Increase distance in Z by the anisotropy
|
|
368
387
|
dist = delta @ delta
|
|
369
388
|
|
|
370
389
|
if dist <= radius[k]:
|
|
@@ -378,6 +397,9 @@ def draw_disk(
|
|
|
378
397
|
positions: np.ndarray,
|
|
379
398
|
identifiers: np.ndarray,
|
|
380
399
|
radius: np.ndarray,
|
|
400
|
+
*,
|
|
401
|
+
anisotropy=1.0,
|
|
402
|
+
overwrite=False,
|
|
381
403
|
):
|
|
382
404
|
"""Draw disks on the segmentation
|
|
383
405
|
|
|
@@ -390,21 +412,27 @@ def draw_disk(
|
|
|
390
412
|
Shape: (n,), dtype: uint16
|
|
391
413
|
radius (np.ndarray): Radius of each disk
|
|
392
414
|
Shape: (n, ), dtype: float32)
|
|
415
|
+
anisotropy (float): Relative size of a pixel along the depth dimension
|
|
416
|
+
versus height/width dimensions.
|
|
417
|
+
Default: 1.0
|
|
418
|
+
overwrite (bool): Overwrite pixels that are already written (!=0)
|
|
419
|
+
Default: False
|
|
420
|
+
|
|
393
421
|
"""
|
|
394
422
|
# Wrapped to redirect in 2D/3D and numba does not support np.indices in 3.8
|
|
395
423
|
if segmentation.ndim == 3:
|
|
396
424
|
thresh = round(radius.max())
|
|
397
425
|
bbox: np.ndarray = np.indices((thresh * 2 + 1, thresh * 2 + 1, thresh * 2 + 1)).transpose(1, 2, 3, 0) - thresh
|
|
398
426
|
bbox = bbox.reshape(-1, 3)
|
|
399
|
-
_fast_disk_3d(segmentation, bbox, positions, identifiers, radius)
|
|
427
|
+
_fast_disk_3d(segmentation, bbox, positions, identifiers, radius, anisoptropy=anisotropy, overwrite=overwrite)
|
|
400
428
|
else:
|
|
401
429
|
thresh = int(round(radius.max()))
|
|
402
430
|
bbox = np.indices((thresh * 2 + 1, thresh * 2 + 1)).transpose(1, 2, 0) - thresh
|
|
403
431
|
bbox = bbox.reshape(-1, 2)
|
|
404
|
-
_fast_disk_2d(segmentation, bbox, positions, identifiers, radius)
|
|
432
|
+
_fast_disk_2d(segmentation, bbox, positions, identifiers, radius, overwrite=overwrite)
|
|
405
433
|
|
|
406
434
|
|
|
407
|
-
def save_tracks( # pylint: disable=too-many-branches,too-many-locals,too-many-statements
|
|
435
|
+
def save_tracks( # pylint: disable=too-many-branches,too-many-locals,too-many-statements,too-many-arguments
|
|
408
436
|
path: Union[str, os.PathLike],
|
|
409
437
|
tracks: Collection[byotrack.Track],
|
|
410
438
|
detections_sequence: Sequence[byotrack.Detections] = (),
|
|
@@ -415,6 +443,8 @@ def save_tracks( # pylint: disable=too-many-branches,too-many-locals,too-many-s
|
|
|
415
443
|
last=0,
|
|
416
444
|
shape: Optional[Tuple[int, ...]] = None,
|
|
417
445
|
n_digit=4,
|
|
446
|
+
anisotropy=1.0,
|
|
447
|
+
overwrite_detections=False,
|
|
418
448
|
):
|
|
419
449
|
"""Save tracks in the CTC format [10]
|
|
420
450
|
|
|
@@ -453,6 +483,11 @@ def save_tracks( # pylint: disable=too-many-branches,too-many-locals,too-many-s
|
|
|
453
483
|
Default: None
|
|
454
484
|
n_digit (int): Number of digit used to encode time in file names.
|
|
455
485
|
Default: 4
|
|
486
|
+
anisotropy (float): Relative size of a pixel along the depth dimension
|
|
487
|
+
versus height/width dimensions.
|
|
488
|
+
Default: 1.0
|
|
489
|
+
overwrite_detections (bool): Overwrite the segmentation of objects with disk.
|
|
490
|
+
Default: False (Disk are only drawn on background)
|
|
456
491
|
|
|
457
492
|
"""
|
|
458
493
|
path = pathlib.Path(path)
|
|
@@ -517,6 +552,8 @@ def save_tracks( # pylint: disable=too-many-branches,too-many-locals,too-many-s
|
|
|
517
552
|
torch.stack(disk_positions).numpy(),
|
|
518
553
|
np.array(disk_ids, dtype=np.uint16) + 1,
|
|
519
554
|
np.full(len(disk_ids), default_radius, dtype=np.float32),
|
|
555
|
+
anisotropy=anisotropy,
|
|
556
|
+
overwrite=overwrite_detections,
|
|
520
557
|
)
|
|
521
558
|
|
|
522
559
|
# Safety checks because CTC is quite restrictive
|
|
@@ -10,16 +10,23 @@ class FijiRunner: # pylint: disable=too-few-public-methods
|
|
|
10
10
|
Attributes:
|
|
11
11
|
fiji_path (str | os.PathLike): Path to the fiji executable
|
|
12
12
|
The executable can be found inside the installation folder of Fiji.
|
|
13
|
-
Linux: Fiji.app/ImageJ-<os
|
|
13
|
+
Linux: Fiji.app/ImageJ-<os>
|
|
14
14
|
Windows: Fiji.app/ImageJ-<os>.exe
|
|
15
15
|
MacOs: Fiji.app/Contents/MacOs/ImageJ-<os>
|
|
16
|
+
capture_outputs (bool): Whether to PIPE stderr and stdout into Python
|
|
17
|
+
This will allow you to find the stdout/stderr inside `last_outputs`.
|
|
18
|
+
But outputs are captured, and you do not see them while the scripts run.
|
|
19
|
+
Default: False
|
|
20
|
+
last_outputs (subprocess.CompletedProcess): Outputs of the last subprocess.run
|
|
16
21
|
|
|
17
22
|
"""
|
|
18
23
|
|
|
19
24
|
cmd = './{fiji} --ij2 --headless --console --run "{script}" "{args}"'
|
|
20
25
|
|
|
21
|
-
def __init__(self, fiji_path: Union[str, os.PathLike]) -> None:
|
|
26
|
+
def __init__(self, fiji_path: Union[str, os.PathLike], capture_outputs=False) -> None:
|
|
22
27
|
self.fiji_path = fiji_path
|
|
28
|
+
self.capture_outputs = capture_outputs
|
|
29
|
+
self.last_outputs: subprocess.CompletedProcess = subprocess.CompletedProcess("", 0)
|
|
23
30
|
|
|
24
31
|
assert os.path.isfile(fiji_path), "Unable to found the given path"
|
|
25
32
|
|
|
@@ -42,4 +49,8 @@ class FijiRunner: # pylint: disable=too-few-public-methods
|
|
|
42
49
|
cmd = cmd[2:] # Strip ./ on windows
|
|
43
50
|
|
|
44
51
|
print("Calling Fiji with:", cmd)
|
|
45
|
-
|
|
52
|
+
self.last_outputs = subprocess.run(
|
|
53
|
+
cmd, check=True, cwd=os.path.dirname(self.fiji_path), shell=True, capture_output=self.capture_outputs
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
return self.last_outputs.returncode
|