Skip to content

Core

The following classes provide the top-performing algorithms from several BraTS challenges. All algorithms support single-subject and batch inference.

Segmentation Algorithms

brats.core.segmentation_algorithms

SegmentationAlgorithm

Bases: BraTSAlgorithm

This class provides algorithms to perform tumor segmentation on MRI data. It is the base class for all segmentation algorithms and provides the common interface for single and batch inference.

Source code in brats/core/segmentation_algorithms.py
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
class SegmentationAlgorithm(BraTSAlgorithm):
    """This class provides algorithms to perform tumor segmentation on MRI data. It is
    the base class for all segmentation algorithms and provides the common interface
    for single and batch inference."""

    def __init__(
        self,
        algorithm: Algorithms,
        algorithms_file_path: Path,
        cuda_devices: str = "0",
        force_cpu: bool = False,
    ):
        super().__init__(
            algorithm=algorithm,
            algorithms_file_path=algorithms_file_path,
            task=Task.SEGMENTATION,
            cuda_devices=cuda_devices,
            force_cpu=force_cpu,
        )

    def _standardize_single_inputs(
        self,
        data_folder: Path,
        subject_id: str,
        inputs: Mapping[str, Path | str],
        subject_modality_separator: str,
    ) -> None:
        """Standardize the input images for a single subject to match requirements
        of all algorithms and save them in @data_folder/@subject_id.
        Example:
            Meaning, e.g. for adult glioma:
                BraTS-GLI-00000-000 \n
                ┣ BraTS-GLI-00000-000-t1c.nii.gz \n
                ┣ BraTS-GLI-00000-000-t1n.nii.gz \n
                ┣ BraTS-GLI-00000-000-t2f.nii.gz \n
                ┗ BraTS-GLI-00000-000-t2w.nii.gz \n

        Args:
            data_folder (Path): Parent folder where the subject folder will
                be created
            subject_id (str): Subject ID to be used for the folder and
                filenames
            inputs (Dict[str, Path | str]): Dictionary with the input images
            subject_modality_separator (str): Separator between the subject
                ID and the modality
        """

        subject_folder = data_folder / subject_id
        subject_folder.mkdir(parents=True, exist_ok=True)
        # TODO: investigate usage of symlinks (might cause issues on windows
        # and would probably require different volume handling)
        try:
            for modality, path in inputs.items():
                shutil.copy(
                    path,
                    subject_folder
                    / f"{subject_id}{subject_modality_separator}{modality}.nii.gz",
                )
        except FileNotFoundError as e:
            logger.error(f"Error while standardizing files: {e}")
            logger.error(
                "If you use batch processing please ensure the input files "
                "are in the correct format, i.e.:\n "
                "A/A-t1c.nii.gz, A/A-t1n.nii.gz, "
                "A/A-t2f.nii.gz, A/A-t2w.nii.gz"
            )
            raise

        # sanity check inputs
        input_sanity_check(
            t1c=inputs.get("t1c"),
            t1n=inputs.get("t1n"),
            t2f=inputs.get("t2f"),
            t2w=inputs.get("t2w"),
        )

    def _standardize_batch_inputs(
        self,
        data_folder: Path,
        subjects: list[Path],
        input_name_schema: str,
        only_t1c: bool = False,
    ) -> dict[str, str]:
        """Standardize the input images for a list of subjects to match requirements
        of all algorithms and save them in @tmp_data_folder/@subject_id.

        Args:
            subjects (List[Path]): List of subject folders, each with a t1c,
                t1n, t2f, t2w image in standard format
            data_folder (Path): Parent folder where the subject folders will
                be created
            input_name_schema (str): Schema to be used for the subject folder
                and filenames depending on the BraTS Challenge
            only_t1c (bool, optional): If True, only the t1c image will be
                used. Defaults to False.

        Returns:
            Dict[str, str]: Dictionary mapping internal name (in standardized
                format) to external subject name provided by user
        """
        internal_external_name_map = {}
        for i, subject in enumerate(subjects):
            internal_name = input_name_schema.format(id=i)
            internal_external_name_map[internal_name] = subject.name

            inputs = {
                "t1c": subject / f"{subject.name}-t1c.nii.gz",
            }
            if not only_t1c:
                inputs["t1n"] = subject / f"{subject.name}-t1n.nii.gz"
                inputs["t2f"] = subject / f"{subject.name}-t2f.nii.gz"
                inputs["t2w"] = subject / f"{subject.name}-t2w.nii.gz"

            self._standardize_single_inputs(
                data_folder=data_folder,
                subject_id=internal_name,
                inputs=inputs,
                subject_modality_separator=self.algorithm.run_args.subject_modality_separator,
            )
        return internal_external_name_map

    @abstractmethod
    def infer_single(
        self,
        *args: object,
        **kwargs: object,
    ) -> None:
        pass

    @abstractmethod
    def infer_batch(
        self,
        data_folder: Path | str,
        output_folder: Path | str,
        log_file: Path | str | None = None,
    ) -> None:
        pass

SegmentationAlgorithmWith4Modalities

Bases: SegmentationAlgorithm

Segmentation algorithm that works with 4 modalities (T1c, T1n, T2f, T2w).

Source code in brats/core/segmentation_algorithms.py
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
class SegmentationAlgorithmWith4Modalities(SegmentationAlgorithm):
    """Segmentation algorithm that works with 4 modalities (T1c, T1n, T2f, T2w)."""

    def infer_single(
        self,
        t1c: Path | str,
        t1n: Path | str,
        t2f: Path | str,
        t2w: Path | str,
        output_file: Path | str,
        log_file: Optional[Path | str] = None,
        backend: Optional[Backends] = Backends.DOCKER,
    ) -> None:
        """Perform segmentation on a single subject with the provided images and save
        the result to the output file.

        Args:
            t1c (Path | str): Path to the T1c image
            t1n (Path | str): Path to the T1n image
            t2f (Path | str): Path to the T2f image
            t2w (Path | str): Path to the T2w image
            output_file (Path | str): Path to save the segmentation
            log_file (Path | str, optional): Save logs to this file
            backend (Backends, optional): Backend to use for inference. Defaults to Backends.DOCKER.
        """

        self._infer_single(
            inputs={"t1c": t1c, "t1n": t1n, "t2f": t2f, "t2w": t2w},
            output_file=output_file,
            log_file=log_file,
            backend=backend,
        )

    def infer_batch(
        self,
        data_folder: Path | str,
        output_folder: Path | str,
        log_file: Path | str | None = None,
        backend: Optional[Backends] = Backends.DOCKER,
    ) -> None:
        """Perform segmentation on a batch of subjects with the provided images
        and save the results to the output folder. \n
        Requires the following structure:\n
        data_folder\n
        ┣ A\n
        ┃ ┣ A-t1c.nii.gz\n
        ┃ ┣ A-t1n.nii.gz\n
        ┃ ┣ A-t2f.nii.gz\n
        ┃ ┗ A-t2w.nii.gz\n
        ┣ B\n
        ┃ ┣ B-t1c.nii.gz\n
        ┃ ┣ ...\n


        Args:
            data_folder (Path | str): Folder containing the subjects with required structure
            output_folder (Path | str): Output folder to save the segmentations
            log_file (Path | str, optional): Save logs to this file
            backend (Backends, optional): Backend to use for inference. Defaults to Backends.DOCKER.
        """

        return self._infer_batch(
            data_folder=data_folder,
            output_folder=output_folder,
            log_file=log_file,
            backend=backend,
        )

infer_single

infer_single(
    t1c: Path | str,
    t1n: Path | str,
    t2f: Path | str,
    t2w: Path | str,
    output_file: Path | str,
    log_file: Optional[Path | str] = None,
    backend: Optional[Backends] = Backends.DOCKER,
) -> None

Perform segmentation on a single subject with the provided images and save the result to the output file.

Parameters:

Name Type Description Default
t1c Path | str

Path to the T1c image

required
t1n Path | str

Path to the T1n image

required
t2f Path | str

Path to the T2f image

required
t2w Path | str

Path to the T2w image

required
output_file Path | str

Path to save the segmentation

required
log_file Path | str

Save logs to this file

None
backend Backends

Backend to use for inference. Defaults to Backends.DOCKER.

DOCKER
Source code in brats/core/segmentation_algorithms.py
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
def infer_single(
    self,
    t1c: Path | str,
    t1n: Path | str,
    t2f: Path | str,
    t2w: Path | str,
    output_file: Path | str,
    log_file: Optional[Path | str] = None,
    backend: Optional[Backends] = Backends.DOCKER,
) -> None:
    """Perform segmentation on a single subject with the provided images and save
    the result to the output file.

    Args:
        t1c (Path | str): Path to the T1c image
        t1n (Path | str): Path to the T1n image
        t2f (Path | str): Path to the T2f image
        t2w (Path | str): Path to the T2w image
        output_file (Path | str): Path to save the segmentation
        log_file (Path | str, optional): Save logs to this file
        backend (Backends, optional): Backend to use for inference. Defaults to Backends.DOCKER.
    """

    self._infer_single(
        inputs={"t1c": t1c, "t1n": t1n, "t2f": t2f, "t2w": t2w},
        output_file=output_file,
        log_file=log_file,
        backend=backend,
    )

infer_batch

infer_batch(
    data_folder: Path | str,
    output_folder: Path | str,
    log_file: Path | str | None = None,
    backend: Optional[Backends] = Backends.DOCKER,
) -> None

Perform segmentation on a batch of subjects with the provided images and save the results to the output folder.

Requires the following structure:

data_folder

┣ A

┃ ┣ A-t1c.nii.gz

┃ ┣ A-t1n.nii.gz

┃ ┣ A-t2f.nii.gz

┃ ┗ A-t2w.nii.gz

┣ B

┃ ┣ B-t1c.nii.gz

┃ ┣ ...

Parameters:

Name Type Description Default
data_folder Path | str

Folder containing the subjects with required structure

required
output_folder Path | str

Output folder to save the segmentations

required
log_file Path | str

Save logs to this file

None
backend Backends

Backend to use for inference. Defaults to Backends.DOCKER.

DOCKER
Source code in brats/core/segmentation_algorithms.py
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
def infer_batch(
    self,
    data_folder: Path | str,
    output_folder: Path | str,
    log_file: Path | str | None = None,
    backend: Optional[Backends] = Backends.DOCKER,
) -> None:
    """Perform segmentation on a batch of subjects with the provided images
    and save the results to the output folder. \n
    Requires the following structure:\n
    data_folder\n
    ┣ A\n
    ┃ ┣ A-t1c.nii.gz\n
    ┃ ┣ A-t1n.nii.gz\n
    ┃ ┣ A-t2f.nii.gz\n
    ┃ ┗ A-t2w.nii.gz\n
    ┣ B\n
    ┃ ┣ B-t1c.nii.gz\n
    ┃ ┣ ...\n


    Args:
        data_folder (Path | str): Folder containing the subjects with required structure
        output_folder (Path | str): Output folder to save the segmentations
        log_file (Path | str, optional): Save logs to this file
        backend (Backends, optional): Backend to use for inference. Defaults to Backends.DOCKER.
    """

    return self._infer_batch(
        data_folder=data_folder,
        output_folder=output_folder,
        log_file=log_file,
        backend=backend,
    )

AdultGliomaPreTreatmentSegmenter

Bases: SegmentationAlgorithmWith4Modalities

Provides algorithms to perform tumor segmentation on adult glioma pre treatment MRI data.

Parameters:

Name Type Description Default
algorithm AdultGliomaPreTreatmentAlgorithms

Select an algorithm. Defaults to AdultGliomaPreTreatmentAlgorithms.BraTS23_1.

BraTS23_1
cuda_devices Optional[str]

Which cuda devices to use. Defaults to "0".

'0'
force_cpu bool

Execution will default to GPU, this flag allows forced CPU execution if the algorithm is compatible. Defaults to False.

False
Source code in brats/core/segmentation_algorithms.py
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
class AdultGliomaPreTreatmentSegmenter(SegmentationAlgorithmWith4Modalities):
    """Provides algorithms to perform tumor segmentation on adult glioma pre
    treatment MRI data.

    Args:
        algorithm (AdultGliomaPreTreatmentAlgorithms, optional): Select an
            algorithm. Defaults to
            AdultGliomaPreTreatmentAlgorithms.BraTS23_1.
        cuda_devices (Optional[str], optional): Which cuda devices to use.
            Defaults to "0".
        force_cpu (bool, optional): Execution will default to GPU, this flag
            allows forced CPU execution if the algorithm is compatible.
            Defaults to False.
    """

    def __init__(
        self,
        algorithm: AdultGliomaPreTreatmentAlgorithms = AdultGliomaPreTreatmentAlgorithms.BraTS23_1,
        cuda_devices: str = "0",
        force_cpu: bool = False,
    ):
        super().__init__(
            algorithm=algorithm,
            algorithms_file_path=ADULT_GLIOMA_PRE_TREATMENT_SEGMENTATION_ALGORITHMS,
            cuda_devices=cuda_devices,
            force_cpu=force_cpu,
        )

AdultGliomaPreAndPostTreatmentSegmenter

Bases: SegmentationAlgorithmWith4Modalities

Provides algorithms to perform tumor segmentation on adult glioma pre and post treatment MRI data.

Parameters:

Name Type Description Default
algorithm AdultGliomaPreAndPostTreatmentAlgorithms

Select an algorithm. Defaults to AdultGliomaPreAndPostTreatmentAlgorithms.BraTS25_1.

BraTS25_1
cuda_devices Optional[str]

Which cuda devices to use. Defaults to "0".

'0'
force_cpu bool

Execution will default to GPU, this flag allows forced CPU execution if the algorithm is compatible. Defaults to False.

False
Source code in brats/core/segmentation_algorithms.py
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
class AdultGliomaPreAndPostTreatmentSegmenter(SegmentationAlgorithmWith4Modalities):
    """Provides algorithms to perform tumor segmentation on adult glioma pre
    and post treatment MRI data.

    Args:
        algorithm (AdultGliomaPreAndPostTreatmentAlgorithms, optional):
            Select an algorithm. Defaults to
            AdultGliomaPreAndPostTreatmentAlgorithms.BraTS25_1.
        cuda_devices (Optional[str], optional): Which cuda devices to use.
            Defaults to "0".
        force_cpu (bool, optional): Execution will default to GPU, this flag
            allows forced CPU execution if the algorithm is compatible.
            Defaults to False.
    """

    def __init__(
        self,
        algorithm: AdultGliomaPreAndPostTreatmentAlgorithms = (
            AdultGliomaPreAndPostTreatmentAlgorithms.BraTS25_1
        ),
        cuda_devices: str = "0",
        force_cpu: bool = False,
    ):
        super().__init__(
            algorithm=algorithm,
            algorithms_file_path=ADULT_GLIOMA_PRE_AND_POST_TREATMENT_SEGMENTATION_ALGORITHMS,
            cuda_devices=cuda_devices,
            force_cpu=force_cpu,
        )

MeningiomaSegmenter

Bases: SegmentationAlgorithmWith4Modalities

Provides algorithms to perform tumor segmentation on adult meningioma MRI data.

Parameters:

Name Type Description Default
algorithm MeningiomaAlgorithms

Select an algorithm. Defaults to MeningiomaAlgorithms.BraTS23_1.

BraTS25_1
cuda_devices Optional[str]

Which cuda devices to use. Defaults to "0".

'0'
force_cpu bool

Execution will default to GPU, this flag allows forced CPU execution if the algorithm is compatible. Defaults to False.

False
Source code in brats/core/segmentation_algorithms.py
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
class MeningiomaSegmenter(SegmentationAlgorithmWith4Modalities):
    """Provides algorithms to perform tumor segmentation on adult meningioma
    MRI data.

    Args:
        algorithm (MeningiomaAlgorithms, optional): Select an algorithm.
            Defaults to MeningiomaAlgorithms.BraTS23_1.
        cuda_devices (Optional[str], optional): Which cuda devices to use.
            Defaults to "0".
        force_cpu (bool, optional): Execution will default to GPU, this flag
            allows forced CPU execution if the algorithm is compatible.
            Defaults to False.
    """

    def __init__(
        self,
        algorithm: MeningiomaAlgorithms = MeningiomaAlgorithms.BraTS25_1,
        cuda_devices: str = "0",
        force_cpu: bool = False,
    ):
        super().__init__(
            algorithm=algorithm,
            algorithms_file_path=MENINGIOMA_SEGMENTATION_ALGORITHMS,
            cuda_devices=cuda_devices,
            force_cpu=force_cpu,
        )

PediatricSegmenter

Bases: SegmentationAlgorithmWith4Modalities

Provides algorithms to perform tumor segmentation on pediatric MRI data

Parameters:

Name Type Description Default
algorithm PediatricAlgorithms

Select an algorithm. Defaults to PediatricAlgorithms.BraTS23_1.

BraTS25_1
cuda_devices Optional[str]

Which cuda devices to use. Defaults to "0".

'0'
force_cpu bool

Execution will default to GPU, this flag allows forced CPU execution if the algorithm is compatible. Defaults to False.

False
Source code in brats/core/segmentation_algorithms.py
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
class PediatricSegmenter(SegmentationAlgorithmWith4Modalities):
    """Provides algorithms to perform tumor segmentation on pediatric MRI data

    Args:
        algorithm (PediatricAlgorithms, optional): Select an algorithm.
            Defaults to PediatricAlgorithms.BraTS23_1.
        cuda_devices (Optional[str], optional): Which cuda devices to use.
            Defaults to "0".
        force_cpu (bool, optional): Execution will default to GPU, this flag
            allows forced CPU execution if the algorithm is compatible.
            Defaults to False.
    """

    def __init__(
        self,
        algorithm: PediatricAlgorithms = PediatricAlgorithms.BraTS25_1,
        cuda_devices: str = "0",
        force_cpu: bool = False,
    ):
        super().__init__(
            algorithm=algorithm,
            algorithms_file_path=PEDIATRIC_SEGMENTATION_ALGORITHMS,
            cuda_devices=cuda_devices,
            force_cpu=force_cpu,
        )

AfricaSegmenter

Bases: SegmentationAlgorithmWith4Modalities

Provides algorithms from the BraTSAfrica challenge

Parameters:

Name Type Description Default
algorithm AfricaAlgorithms

Select an algorithm. Defaults to AfricaAlgorithms.BraTS23_1.

BraTS25_1
cuda_devices Optional[str]

Which cuda devices to use. Defaults to "0".

'0'
force_cpu bool

Execution will default to GPU, this flag allows forced CPU execution if the algorithm is compatible. Defaults to False.

False
Source code in brats/core/segmentation_algorithms.py
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
class AfricaSegmenter(SegmentationAlgorithmWith4Modalities):
    """Provides algorithms from the BraTSAfrica challenge

    Args:
        algorithm (AfricaAlgorithms, optional): Select an algorithm.
            Defaults to AfricaAlgorithms.BraTS23_1.
        cuda_devices (Optional[str], optional): Which cuda devices to use.
            Defaults to "0".
        force_cpu (bool, optional): Execution will default to GPU, this flag
            allows forced CPU execution if the algorithm is compatible.
            Defaults to False.
    """

    def __init__(
        self,
        algorithm: AfricaAlgorithms = AfricaAlgorithms.BraTS25_1,
        cuda_devices: str = "0",
        force_cpu: bool = False,
    ):
        super().__init__(
            algorithm=algorithm,
            algorithms_file_path=AFRICA_SEGMENTATION_ALGORITHMS,
            cuda_devices=cuda_devices,
            force_cpu=force_cpu,
        )

MetastasesSegmenter

Bases: SegmentationAlgorithmWith4Modalities

Provides algorithms from the Brain Metastases Segmentation challenge

Parameters:

Name Type Description Default
algorithm MetastasesAlgorithms

Select an algorithm. Defaults to MetastasesAlgorithms.BraTS23_1.

BraTS25_1
cuda_devices Optional[str]

Which cuda devices to use. Defaults to "0".

'0'
force_cpu bool

Execution will default to GPU, this flag allows forced CPU execution if the algorithm is compatible. Defaults to False.

False
Source code in brats/core/segmentation_algorithms.py
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
class MetastasesSegmenter(SegmentationAlgorithmWith4Modalities):
    """Provides algorithms from the Brain Metastases Segmentation challenge

    Args:
        algorithm (MetastasesAlgorithms, optional): Select an algorithm.
            Defaults to MetastasesAlgorithms.BraTS23_1.
        cuda_devices (Optional[str], optional): Which cuda devices to use.
            Defaults to "0".
        force_cpu (bool, optional): Execution will default to GPU, this flag
            allows forced CPU execution if the algorithm is compatible.
            Defaults to False.
    """

    def __init__(
        self,
        algorithm: MetastasesAlgorithms = MetastasesAlgorithms.BraTS25_1,
        cuda_devices: str = "0",
        force_cpu: bool = False,
    ):
        super().__init__(
            algorithm=algorithm,
            algorithms_file_path=METASTASES_SEGMENTATION_ALGORITHMS,
            cuda_devices=cuda_devices,
            force_cpu=force_cpu,
        )

GoATSegmenter

Bases: SegmentationAlgorithmWith4Modalities

Provides algorithms from the BraTS Generalizability Across Tumors (BraTS-GoAT)

Parameters:

Name Type Description Default
algorithm GoATAlgorithms

Select an algorithm. Defaults to GoATAlgorithms.BraTS23_1.

BraTS25_1A
cuda_devices Optional[str]

Which cuda devices to use. Defaults to "0".

'0'
force_cpu bool

Execution will default to GPU, this flag allows forced CPU execution if the algorithm is compatible. Defaults to False.

False
Source code in brats/core/segmentation_algorithms.py
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
class GoATSegmenter(SegmentationAlgorithmWith4Modalities):
    """Provides algorithms from the BraTS Generalizability Across Tumors
    (BraTS-GoAT)

    Args:
        algorithm (GoATAlgorithms, optional): Select an algorithm.
            Defaults to GoATAlgorithms.BraTS23_1.
        cuda_devices (Optional[str], optional): Which cuda devices to use.
            Defaults to "0".
        force_cpu (bool, optional): Execution will default to GPU, this flag
            allows forced CPU execution if the algorithm is compatible.
            Defaults to False.
    """

    def __init__(
        self,
        algorithm: GoATAlgorithms = GoATAlgorithms.BraTS25_1A,
        cuda_devices: str = "0",
        force_cpu: bool = False,
    ):
        super().__init__(
            algorithm=algorithm,
            algorithms_file_path=GOAT_SEGMENTATION_ALGORITHMS,
            cuda_devices=cuda_devices,
            force_cpu=force_cpu,
        )

MeningiomaRTSegmenter

Bases: SegmentationAlgorithm

Provides algorithms to perform tumor segmentation on adult meningioma Radio Therapy MRI data.

Parameters:

Name Type Description Default
algorithm MeningiomaRTAlgorithms

Select an algorithm. Defaults to MeningiomaRTAlgorithms.BraTS25_1.

BraTS25_1
cuda_devices Optional[str]

Which cuda devices to use. Defaults to "0".

'0'
force_cpu bool

Execution will default to GPU, this flag allows forced CPU execution if the algorithm is compatible. Defaults to False.

False
Source code in brats/core/segmentation_algorithms.py
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
class MeningiomaRTSegmenter(SegmentationAlgorithm):
    """Provides algorithms to perform tumor segmentation on adult meningioma
    Radio Therapy MRI data.

    Args:
        algorithm (MeningiomaRTAlgorithms, optional): Select an algorithm.
            Defaults to MeningiomaRTAlgorithms.BraTS25_1.
        cuda_devices (Optional[str], optional): Which cuda devices to use.
            Defaults to "0".
        force_cpu (bool, optional): Execution will default to GPU, this flag
            allows forced CPU execution if the algorithm is compatible.
            Defaults to False.
    """

    def __init__(
        self,
        algorithm: MeningiomaRTAlgorithms = MeningiomaRTAlgorithms.BraTS25_1,
        cuda_devices: str = "0",
        force_cpu: bool = False,
    ):
        super().__init__(
            algorithm=algorithm,
            algorithms_file_path=MENINGIOMA_RT_SEGMENTATION_ALGORITHMS,
            cuda_devices=cuda_devices,
            force_cpu=force_cpu,
        )

    def _standardize_batch_inputs(
        self,
        data_folder: Path,
        subjects: list[Path],
        input_name_schema: str,
        only_t1c: bool = False,
    ) -> dict[str, str]:
        """Standardize the input images for a list of subjects to match requirements
        of all algorithms and save them in @tmp_data_folder/@subject_id.

        Args:
            subjects (List[Path]): List of subject folders, each with a t1c
                image in standard format
            data_folder (Path): Parent folder where the subject folders will
                be created
            input_name_schema (str): Schema to be used for the subject folder
                and filenames depending on the BraTS Challenge

        Returns:
            Dict[str, str]: Dictionary mapping internal name (in standardized
                format) to external subject name provided by user
        """
        return super()._standardize_batch_inputs(
            data_folder=data_folder,
            subjects=subjects,
            input_name_schema=input_name_schema,
            only_t1c=True,
        )

    def infer_single(
        self,
        t1c: Union[Path, str],
        output_file: Path | str,
        log_file: Optional[Path | str] = None,
        backend: Optional[Backends] = Backends.DOCKER,
    ) -> None:
        """
        Perform segmentation on a single subject with the provided T1C image
        and save the result to the output file.

        Args:
            t1c (Path | str): Path to the T1c image
            output_file (Path | str): Output file to save the segmentation.
            log_file (Optional[Path | str], optional): Save logs to this file. Defaults to None.
            backend (Backends, optional): Backend to use for inference. Defaults to Backends.DOCKER.
        """

        self._infer_single(
            inputs={"t1c": t1c},
            output_file=output_file,
            log_file=log_file,
            backend=backend,
        )

    def infer_batch(
        self,
        data_folder: Path | str,
        output_folder: Path | str,
        log_file: Path | str | None = None,
        backend: Optional[Backends] = Backends.DOCKER,
    ) -> None:
        """
        Perform segmentation on a batch of subjects with the provided T1C
        images and save the results to the output folder. \n


        Requires the following structure:\n
        data_folder\n
        ┣ A\n
        ┃ ┗ A-t1c.nii.gz\n
        ┣ B\n
        ┃ ┗ B-t1c.nii.gz\n
        ┃ ...\n


        Args:
            data_folder (Path | str): Folder containing the subjects with required structure
            output_folder (Path | str): Output folder to save the segmentations
            log_file (Path | str, optional): Save logs to this file
            backend (Backends, optional): Backend to use for inference. Defaults to Backends.DOCKER.
        """

        return self._infer_batch(
            data_folder=data_folder,
            output_folder=output_folder,
            log_file=log_file,
            backend=backend,
        )

infer_single

infer_single(
    t1c: Union[Path, str],
    output_file: Path | str,
    log_file: Optional[Path | str] = None,
    backend: Optional[Backends] = Backends.DOCKER,
) -> None

Perform segmentation on a single subject with the provided T1C image and save the result to the output file.

Parameters:

Name Type Description Default
t1c Path | str

Path to the T1c image

required
output_file Path | str

Output file to save the segmentation.

required
log_file Optional[Path | str]

Save logs to this file. Defaults to None.

None
backend Backends

Backend to use for inference. Defaults to Backends.DOCKER.

DOCKER
Source code in brats/core/segmentation_algorithms.py
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
def infer_single(
    self,
    t1c: Union[Path, str],
    output_file: Path | str,
    log_file: Optional[Path | str] = None,
    backend: Optional[Backends] = Backends.DOCKER,
) -> None:
    """
    Perform segmentation on a single subject with the provided T1C image
    and save the result to the output file.

    Args:
        t1c (Path | str): Path to the T1c image
        output_file (Path | str): Output file to save the segmentation.
        log_file (Optional[Path | str], optional): Save logs to this file. Defaults to None.
        backend (Backends, optional): Backend to use for inference. Defaults to Backends.DOCKER.
    """

    self._infer_single(
        inputs={"t1c": t1c},
        output_file=output_file,
        log_file=log_file,
        backend=backend,
    )

infer_batch

infer_batch(
    data_folder: Path | str,
    output_folder: Path | str,
    log_file: Path | str | None = None,
    backend: Optional[Backends] = Backends.DOCKER,
) -> None

Perform segmentation on a batch of subjects with the provided T1C images and save the results to the output folder.

Requires the following structure:

data_folder

┣ A

┃ ┗ A-t1c.nii.gz

┣ B

┃ ┗ B-t1c.nii.gz

┃ ...

Parameters:

Name Type Description Default
data_folder Path | str

Folder containing the subjects with required structure

required
output_folder Path | str

Output folder to save the segmentations

required
log_file Path | str

Save logs to this file

None
backend Backends

Backend to use for inference. Defaults to Backends.DOCKER.

DOCKER
Source code in brats/core/segmentation_algorithms.py
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
def infer_batch(
    self,
    data_folder: Path | str,
    output_folder: Path | str,
    log_file: Path | str | None = None,
    backend: Optional[Backends] = Backends.DOCKER,
) -> None:
    """
    Perform segmentation on a batch of subjects with the provided T1C
    images and save the results to the output folder. \n


    Requires the following structure:\n
    data_folder\n
    ┣ A\n
    ┃ ┗ A-t1c.nii.gz\n
    ┣ B\n
    ┃ ┗ B-t1c.nii.gz\n
    ┃ ...\n


    Args:
        data_folder (Path | str): Folder containing the subjects with required structure
        output_folder (Path | str): Output folder to save the segmentations
        log_file (Path | str, optional): Save logs to this file
        backend (Backends, optional): Backend to use for inference. Defaults to Backends.DOCKER.
    """

    return self._infer_batch(
        data_folder=data_folder,
        output_folder=output_folder,
        log_file=log_file,
        backend=backend,
    )

Inpainting Algorithms

brats.core.inpainting_algorithms

Inpainter

Bases: BraTSAlgorithm

Source code in brats/core/inpainting_algorithms.py
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
class Inpainter(BraTSAlgorithm):
    def __init__(
        self,
        algorithm: InpaintingAlgorithms = InpaintingAlgorithms.BraTS23_1,
        cuda_devices: str = "0",
        force_cpu: bool = False,
    ):
        super().__init__(
            algorithm=algorithm,
            algorithms_file_path=INPAINTING_ALGORITHMS,
            task=Task.INPAINTING,
            cuda_devices=cuda_devices,
            force_cpu=force_cpu,
        )

    def _standardize_single_inputs(
        self,
        data_folder: Path,
        subject_id: str,
        inputs: dict[str, Path | str],
        subject_modality_separator: str,
    ) -> None:
        """
        Standardize the input data to match the requirements of the selected algorithm.

        Args:
            data_folder (Path): Path to the data folder
            subject_id (str): Subject ID
            inputs (dict[str, Path | str]): Dictionary with the input data
            subject_modality_separator (str): Separator between the subject ID and the modality
        """

        subject_folder = data_folder / subject_id
        subject_folder.mkdir(parents=True, exist_ok=True)
        # TODO: investigate usage of symlinks (might cause issues on windows
        # and would probably require different volume handling)
        t1n, mask = inputs["t1n"], inputs["mask"]
        try:
            shutil.copy(
                t1n,
                subject_folder
                / f"{subject_id}{subject_modality_separator}t1n-voided.nii.gz",
            )
            shutil.copy(
                mask,
                subject_folder / f"{subject_id}{subject_modality_separator}mask.nii.gz",
            )
        except FileNotFoundError as e:
            logger.error(f"Error while standardizing files: {e}")
            raise

        # sanity check inputs
        input_sanity_check(t1n=t1n, mask=mask)

    def _standardize_batch_inputs(
        self, data_folder: Path, subjects: list[Path], input_name_schema: str
    ) -> dict[str, str]:
        """Standardize the input images for a list of subjects to match requirements
        of all algorithms and save them in @tmp_data_folder/@subject_id.

        Args:
            subjects (List[Path]): List of subject folders, each with a voided
                t1n and a mask image
            data_folder (Path): Parent folder where the subject folders will
                be created
            input_name_schema (str): Schema to be used for the subject folder
                and filenames depending on the BraTS Challenge

        Returns:
            Dict[str, str]: Dictionary mapping internal name (in standardized
                format) to external subject name provided by user
        """
        internal_external_name_map = {}
        for i, subject in enumerate(subjects):
            internal_name = input_name_schema.format(id=i)
            internal_external_name_map[internal_name] = subject.name
            # TODO Add support for .nii files

            self._standardize_single_inputs(
                data_folder=data_folder,
                subject_id=internal_name,
                inputs={
                    "t1n": subject / f"{subject.name}-t1n-voided.nii.gz",
                    "mask": subject / f"{subject.name}-mask.nii.gz",
                },
                subject_modality_separator=self.algorithm.run_args.subject_modality_separator,
            )
        return internal_external_name_map

    def infer_single(
        self,
        t1n: Path | str,
        mask: Path | str,
        output_file: Path | str,
        log_file: Optional[Path | str] = None,
        backend: Optional[Backends] = Backends.DOCKER,
    ) -> None:
        """Perform inpainting task on a single subject with the provided images
        and save the result to the output file.

        Args:
            t1n (Path | str): Path to the voided T1n image
            mask (Path | str): Path to the mask image
            output_file (Path | str): Path to save the segmentation
            log_file (Path | str, optional): Save logs to this file
            backend (Backends, optional): Backend to use for inference. Defaults to Backends.DOCKER.
        """

        self._infer_single(
            inputs={"t1n": t1n, "mask": mask},
            output_file=output_file,
            log_file=log_file,
            backend=backend,
        )

    def infer_batch(
        self,
        data_folder: Path | str,
        output_folder: Path | str,
        log_file: Path | str | None = None,
        backend: Optional[Backends] = Backends.DOCKER,
    ) -> None:
        """Perform inpainting on a batch of subjects with the provided images
        and save the results to the output folder. \n
        Requires the following structure:\n
        data_folder\n
        ┣ A\n
        ┃ ┣ A-t1n-voided.nii.gz\n
        ┃ ┣ A-mask.nii.gz\n
        ┣ B\n
        ┃ ┣ B-t1n-voided.nii.gz\n
        ┃ ┣ B-mask.nii.gz\n
        ┣ C ...\n


        Args:
            data_folder (Path | str): Folder containing the subjects with required structure
            output_folder (Path | str): Output folder to save the segmentations
            log_file (Path | str, optional): Save logs to this file
            backend (Backends, optional): Backend to use for inference. Defaults to Backends.DOCKER.
        """

        return self._infer_batch(
            data_folder=data_folder,
            output_folder=output_folder,
            log_file=log_file,
            backend=backend,
        )

infer_single

infer_single(
    t1n: Path | str,
    mask: Path | str,
    output_file: Path | str,
    log_file: Optional[Path | str] = None,
    backend: Optional[Backends] = Backends.DOCKER,
) -> None

Perform inpainting task on a single subject with the provided images and save the result to the output file.

Parameters:

Name Type Description Default
t1n Path | str

Path to the voided T1n image

required
mask Path | str

Path to the mask image

required
output_file Path | str

Path to save the segmentation

required
log_file Path | str

Save logs to this file

None
backend Backends

Backend to use for inference. Defaults to Backends.DOCKER.

DOCKER
Source code in brats/core/inpainting_algorithms.py
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
def infer_single(
    self,
    t1n: Path | str,
    mask: Path | str,
    output_file: Path | str,
    log_file: Optional[Path | str] = None,
    backend: Optional[Backends] = Backends.DOCKER,
) -> None:
    """Perform inpainting task on a single subject with the provided images
    and save the result to the output file.

    Args:
        t1n (Path | str): Path to the voided T1n image
        mask (Path | str): Path to the mask image
        output_file (Path | str): Path to save the segmentation
        log_file (Path | str, optional): Save logs to this file
        backend (Backends, optional): Backend to use for inference. Defaults to Backends.DOCKER.
    """

    self._infer_single(
        inputs={"t1n": t1n, "mask": mask},
        output_file=output_file,
        log_file=log_file,
        backend=backend,
    )

infer_batch

infer_batch(
    data_folder: Path | str,
    output_folder: Path | str,
    log_file: Path | str | None = None,
    backend: Optional[Backends] = Backends.DOCKER,
) -> None

Perform inpainting on a batch of subjects with the provided images and save the results to the output folder.

Requires the following structure:

data_folder

┣ A

┃ ┣ A-t1n-voided.nii.gz

┃ ┣ A-mask.nii.gz

┣ B

┃ ┣ B-t1n-voided.nii.gz

┃ ┣ B-mask.nii.gz

┣ C ...

Parameters:

Name Type Description Default
data_folder Path | str

Folder containing the subjects with required structure

required
output_folder Path | str

Output folder to save the segmentations

required
log_file Path | str

Save logs to this file

None
backend Backends

Backend to use for inference. Defaults to Backends.DOCKER.

DOCKER
Source code in brats/core/inpainting_algorithms.py
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
def infer_batch(
    self,
    data_folder: Path | str,
    output_folder: Path | str,
    log_file: Path | str | None = None,
    backend: Optional[Backends] = Backends.DOCKER,
) -> None:
    """Perform inpainting on a batch of subjects with the provided images
    and save the results to the output folder. \n
    Requires the following structure:\n
    data_folder\n
    ┣ A\n
    ┃ ┣ A-t1n-voided.nii.gz\n
    ┃ ┣ A-mask.nii.gz\n
    ┣ B\n
    ┃ ┣ B-t1n-voided.nii.gz\n
    ┃ ┣ B-mask.nii.gz\n
    ┣ C ...\n


    Args:
        data_folder (Path | str): Folder containing the subjects with required structure
        output_folder (Path | str): Output folder to save the segmentations
        log_file (Path | str, optional): Save logs to this file
        backend (Backends, optional): Backend to use for inference. Defaults to Backends.DOCKER.
    """

    return self._infer_batch(
        data_folder=data_folder,
        output_folder=output_folder,
        log_file=log_file,
        backend=backend,
    )

Missing MRI Algorithms

brats.core.missing_mri_algorithms

MissingMRI

Bases: BraTSAlgorithm

Source code in brats/core/missing_mri_algorithms.py
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
class MissingMRI(BraTSAlgorithm):
    def __init__(
        self,
        algorithm: MissingMRIAlgorithms = MissingMRIAlgorithms.BraTS24_1,
        cuda_devices: str = "0",
        force_cpu: bool = False,
    ):
        super().__init__(
            algorithm=algorithm,
            algorithms_file_path=MISSING_MRI_ALGORITHMS,
            task=Task.MISSING_MRI,
            cuda_devices=cuda_devices,
            force_cpu=force_cpu,
        )

    def _standardize_single_inputs(
        self,
        data_folder: Path,
        subject_id: str,
        inputs: dict[str, Path | str],
        subject_modality_separator: str,
    ) -> None:
        """
        Standardize the input data to match the requirements of the selected algorithm.

        Args:
            data_folder (Path): Path to the data folder
            subject_id (str): Subject ID
            inputs (dict[str, Path | str]): Dictionary with the input data
            subject_modality_separator (str): Separator between the subject ID and the modality
        """

        subject_folder = data_folder / subject_id
        subject_folder.mkdir(parents=True, exist_ok=True)

        try:
            for modality, path in inputs.items():
                shutil.copy(
                    path,
                    subject_folder
                    / f"{subject_id}{subject_modality_separator}{modality}.nii.gz",
                )
        except FileNotFoundError as e:
            logger.error(f"Error while standardizing files: {e}")
            raise

        # sanity check inputs
        input_sanity_check(
            t1c=inputs.get("t1c"),
            t1n=inputs.get("t1n"),
            t2f=inputs.get("t2f"),
            t2w=inputs.get("t2w"),
        )

    def _standardize_batch_inputs(
        self,
        data_folder: Path,
        subjects: list[Path],
        input_name_schema: str,
    ) -> dict[str, str]:
        """Standardize the input images for a list of subjects to match requirements
        of all algorithms and save them in @tmp_data_folder/@subject_id.

        Args:
            subjects (List[Path]): List of subject folders, each with a t1c,
                t1n, t2f, t2w image in standard format
            data_folder (Path): Parent folder where the subject folders will
                be created
            input_name_schema (str): Schema to be used for the subject folder
                and filenames depending on the BraTS Challenge

        Returns:
            Dict[str, str]: Dictionary mapping internal name (in standardized
                format) to external subject name provided by user
        """
        internal_external_name_map = {}
        for i, subject in enumerate(subjects):
            internal_name = input_name_schema.format(id=i)
            internal_external_name_map[internal_name] = subject.name

            # find relevant files in the subject folder
            possible_inputs = {
                "t1c": subject / f"{subject.name}-t1c.nii.gz",
                "t1n": subject / f"{subject.name}-t1n.nii.gz",
                "t2f": subject / f"{subject.name}-t2f.nii.gz",
                "t2w": subject / f"{subject.name}-t2w.nii.gz",
            }
            valid_inputs: dict[str, Path | str] = {
                k: v for k, v in possible_inputs.items() if v.exists()
            }
            assert len(valid_inputs) == 3, (
                "Exactly 3 inputs are required to perform synthesis of the missing modality"
            )

            self._standardize_single_inputs(
                data_folder=data_folder,
                subject_id=internal_name,
                inputs=valid_inputs,
                subject_modality_separator=self.algorithm.run_args.subject_modality_separator,
            )
        return internal_external_name_map

    def infer_single(
        self,
        output_file: Path | str,
        t1c: Optional[Union[Path, str]] = None,
        t1n: Optional[Union[Path, str]] = None,
        t2f: Optional[Union[Path, str]] = None,
        t2w: Optional[Union[Path, str]] = None,
        log_file: Optional[Path | str] = None,
        backend: Optional[Backends] = Backends.DOCKER,
    ) -> None:
        """
        Perform synthesis of the missing modality for a single subject with the
        provided images and save the result to the output file.

        Note:
            Exactly 3 input modalities are required to perform synthesis of the missing modality.

        Args:
            output_file (Path | str): Output file to save the synthesized image
            t1c (Optional[Union[Path, str]], optional): Path to the T1c image. Defaults to None.
            t1n (Optional[Union[Path, str]], optional): Path to the T1n image. Defaults to None.
            t2f (Optional[Union[Path, str]], optional): Path to the T2f image. Defaults to None.
            t2w (Optional[Union[Path, str]], optional): Path to the T2w image. Defaults to None.
            log_file (Optional[Path | str], optional): Save logs to this file. Defaults to None.
            backend (Backends, optional): Backend to use for inference. Defaults to Backends.DOCKER.
        """

        raw_inputs = {"t1c": t1c, "t1n": t1n, "t2f": t2f, "t2w": t2w}
        # filter out None values
        inputs = {k: v for k, v in raw_inputs.items() if v is not None}

        # assert exactly 3 inputs are given (to compute the missing one)
        assert len(inputs) == 3, (
            "Exactly 3 inputs are required to perform synthesis of the missing modality"
        )

        self._infer_single(
            inputs=inputs,
            output_file=output_file,
            log_file=log_file,
            backend=backend,
        )

    def infer_batch(
        self,
        data_folder: Path | str,
        output_folder: Path | str,
        log_file: Path | str | None = None,
        backend: Optional[Backends] = Backends.DOCKER,
    ) -> None:
        """Perform synthesis on a batch of subjects with the provided images
        and save the results to the output folder. \n

        Requires the following structure (if e.g. t2f should be synthesized):\n
        data_folder\n
        ┣ A\n
        ┃ ┣ A-t1c.nii.gz\n
        ┃ ┣ A-t1n.nii.gz\n
        ┃ ┗ A-t2w.nii.gz\n
        ┣ B\n
        ┃ ┣ B-t1c.nii.gz\n
        ┃ ┣ ...\n


        Args:
            data_folder (Path | str): Folder containing the subjects with required structure
            output_folder (Path | str): Output folder to save the segmentation
            log_file (Path | str, optional): Save logs to this file
            backend (Backends, optional): Backend to use for inference. Defaults to Backends.DOCKER.
        """

        return self._infer_batch(
            data_folder=data_folder,
            output_folder=output_folder,
            log_file=log_file,
            backend=backend,
        )

infer_single

infer_single(
    output_file: Path | str,
    t1c: Optional[Union[Path, str]] = None,
    t1n: Optional[Union[Path, str]] = None,
    t2f: Optional[Union[Path, str]] = None,
    t2w: Optional[Union[Path, str]] = None,
    log_file: Optional[Path | str] = None,
    backend: Optional[Backends] = Backends.DOCKER,
) -> None

Perform synthesis of the missing modality for a single subject with the provided images and save the result to the output file.

Note

Exactly 3 input modalities are required to perform synthesis of the missing modality.

Parameters:

Name Type Description Default
output_file Path | str

Output file to save the synthesized image

required
t1c Optional[Union[Path, str]]

Path to the T1c image. Defaults to None.

None
t1n Optional[Union[Path, str]]

Path to the T1n image. Defaults to None.

None
t2f Optional[Union[Path, str]]

Path to the T2f image. Defaults to None.

None
t2w Optional[Union[Path, str]]

Path to the T2w image. Defaults to None.

None
log_file Optional[Path | str]

Save logs to this file. Defaults to None.

None
backend Backends

Backend to use for inference. Defaults to Backends.DOCKER.

DOCKER
Source code in brats/core/missing_mri_algorithms.py
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
def infer_single(
    self,
    output_file: Path | str,
    t1c: Optional[Union[Path, str]] = None,
    t1n: Optional[Union[Path, str]] = None,
    t2f: Optional[Union[Path, str]] = None,
    t2w: Optional[Union[Path, str]] = None,
    log_file: Optional[Path | str] = None,
    backend: Optional[Backends] = Backends.DOCKER,
) -> None:
    """
    Perform synthesis of the missing modality for a single subject with the
    provided images and save the result to the output file.

    Note:
        Exactly 3 input modalities are required to perform synthesis of the missing modality.

    Args:
        output_file (Path | str): Output file to save the synthesized image
        t1c (Optional[Union[Path, str]], optional): Path to the T1c image. Defaults to None.
        t1n (Optional[Union[Path, str]], optional): Path to the T1n image. Defaults to None.
        t2f (Optional[Union[Path, str]], optional): Path to the T2f image. Defaults to None.
        t2w (Optional[Union[Path, str]], optional): Path to the T2w image. Defaults to None.
        log_file (Optional[Path | str], optional): Save logs to this file. Defaults to None.
        backend (Backends, optional): Backend to use for inference. Defaults to Backends.DOCKER.
    """

    raw_inputs = {"t1c": t1c, "t1n": t1n, "t2f": t2f, "t2w": t2w}
    # filter out None values
    inputs = {k: v for k, v in raw_inputs.items() if v is not None}

    # assert exactly 3 inputs are given (to compute the missing one)
    assert len(inputs) == 3, (
        "Exactly 3 inputs are required to perform synthesis of the missing modality"
    )

    self._infer_single(
        inputs=inputs,
        output_file=output_file,
        log_file=log_file,
        backend=backend,
    )

infer_batch

infer_batch(
    data_folder: Path | str,
    output_folder: Path | str,
    log_file: Path | str | None = None,
    backend: Optional[Backends] = Backends.DOCKER,
) -> None

Perform synthesis on a batch of subjects with the provided images and save the results to the output folder.

Requires the following structure (if e.g. t2f should be synthesized):

data_folder

┣ A

┃ ┣ A-t1c.nii.gz

┃ ┣ A-t1n.nii.gz

┃ ┗ A-t2w.nii.gz

┣ B

┃ ┣ B-t1c.nii.gz

┃ ┣ ...

Parameters:

Name Type Description Default
data_folder Path | str

Folder containing the subjects with required structure

required
output_folder Path | str

Output folder to save the segmentation

required
log_file Path | str

Save logs to this file

None
backend Backends

Backend to use for inference. Defaults to Backends.DOCKER.

DOCKER
Source code in brats/core/missing_mri_algorithms.py
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
def infer_batch(
    self,
    data_folder: Path | str,
    output_folder: Path | str,
    log_file: Path | str | None = None,
    backend: Optional[Backends] = Backends.DOCKER,
) -> None:
    """Perform synthesis on a batch of subjects with the provided images
    and save the results to the output folder. \n

    Requires the following structure (if e.g. t2f should be synthesized):\n
    data_folder\n
    ┣ A\n
    ┃ ┣ A-t1c.nii.gz\n
    ┃ ┣ A-t1n.nii.gz\n
    ┃ ┗ A-t2w.nii.gz\n
    ┣ B\n
    ┃ ┣ B-t1c.nii.gz\n
    ┃ ┣ ...\n


    Args:
        data_folder (Path | str): Folder containing the subjects with required structure
        output_folder (Path | str): Output folder to save the segmentation
        log_file (Path | str, optional): Save logs to this file
        backend (Backends, optional): Backend to use for inference. Defaults to Backends.DOCKER.
    """

    return self._infer_batch(
        data_folder=data_folder,
        output_folder=output_folder,
        log_file=log_file,
        backend=backend,
    )

Abstract Base Class

brats.core.brats_algorithm

BraTSAlgorithm

Bases: ABC

This class serves as the basis for all BraTS algorithms. It provides a common interface and implements the logic for single and batch inference.

Source code in brats/core/brats_algorithm.py
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
class BraTSAlgorithm(ABC):
    """
    This class serves as the basis for all BraTS algorithms. It provides a common
    interface and implements the logic for single and batch inference.
    """

    def __init__(
        self,
        algorithm: Algorithms,
        algorithms_file_path: Path,
        task: Task,
        cuda_devices: str = "0",
        force_cpu: bool = False,
    ):
        # inference device setup
        self.force_cpu = force_cpu
        self.cuda_devices = cuda_devices

        self.task = task
        self.algorithm_list = load_algorithms(file_path=algorithms_file_path)
        # save algorithm identifier for logging etc.
        self.algorithm_key = algorithm.value
        if self.algorithm_key not in self.algorithm_list:
            raise AlgorithmConfigException(
                f"Algorithm {self.algorithm_key} not found in {algorithms_file_path}"
            )
        # data for selected algorithm
        self.algorithm = self.algorithm_list[algorithm.value]

        logger.info(
            f"Instantiated {self.__class__.__name__} with algorithm: "
            f"{self.algorithm_key} by {self.algorithm.meta.authors}"
        )

    @abstractmethod
    def _standardize_single_inputs(
        self,
        data_folder: Path,
        subject_id: str,
        inputs: dict[str, Path | str],
        subject_modality_separator: str,
    ) -> None:
        """
        Standardize the input data to match the requirements of the selected algorithm.
        """

    @abstractmethod
    def _standardize_batch_inputs(
        self, data_folder: Path, subjects: list[Path], input_name_schema: str
    ) -> dict[str, str]:
        """
        Standardize the input data to match the requirements of the selected algorithm.
        """

    def extract_identifier_from_subject_id(self, subject_id: str) -> str:
        """
        Extract the index from the subject ID
        Args:
            subject_id (str): Subject ID of the input
        Returns:
            str: Extracted identifier
        """
        return "-".join(subject_id.split("-")[-2:])

    def _process_single_output(
        self,
        tmp_output_folder: Path | str,
        subject_id: str,
        output_file: Path,
    ) -> None:
        """
        Process the output of a single inference run and save it in the specified file.

        Args:
            tmp_output_folder (Path | str): Folder with the algorithm output
            subject_id (str): Subject ID of the output
            output_file (Path): Path to the desired output file
        """
        # rename output
        if self.task == Task.MISSING_MRI:
            # Missing MRI has no fixed names since the missing modality
            # differs and is included in the name
            algorithm_output = Path(tmp_output_folder).iterdir().__next__()
        else:
            # extract id from subject id, i.e. BraTS-MEN-00000-000 => 00000-000
            identifier = self.extract_identifier_from_subject_id(subject_id)
            possible_output = list(Path(tmp_output_folder).glob(f"*{identifier}*"))
            if len(possible_output) == 0:
                raise FileNotFoundError(
                    f"No output found for subject {subject_id} in {tmp_output_folder}"
                )
            algorithm_output = possible_output[0]

        # ensure path exists and rename output to the desired path
        output_file = Path(output_file).absolute()
        output_file.parent.mkdir(parents=True, exist_ok=True)
        shutil.move(algorithm_output, output_file)

    def _process_batch_output(
        self,
        tmp_output_folder: Path | str,
        output_folder: Path,
        mapping: dict[str, str],
    ) -> None:
        """
        Process the outputs of a batch inference run and save them in the specified folder.

        Args:
            tmp_output_folder (Path | str): Folder with the algorithm outputs
            output_folder (Path): Folder to save the outputs
            mapping (dict[str, str]): Mapping from internal to external subject names
        """
        # move outputs and change name back to initially provided one
        output_folder = Path(output_folder)
        output_folder.mkdir(parents=True, exist_ok=True)
        for internal_name, external_name in mapping.items():
            if self.task == Task.MISSING_MRI:
                # Missing MRI has no fixed names since the missing modality differs
                # and is included in the name
                algorithm_output = (
                    Path(tmp_output_folder).glob(f"*{internal_name}*").__next__()
                )
                try:
                    modality = algorithm_output.name.split("-")[-1].split(".")[0]
                except IndexError:
                    logger.warning(
                        f"Could not extract modality from {algorithm_output.name}"
                    )
                    modality = None
                output_file = (
                    output_folder
                    / f"{external_name}{'-' + modality if modality else ''}.nii.gz"
                )
            else:
                identifier = self.extract_identifier_from_subject_id(internal_name)
                possible_outputs = list(Path(tmp_output_folder).glob(f"*{identifier}*"))
                if len(possible_outputs) == 0:
                    logger.error(
                        f"No output found for subject {internal_name} in {tmp_output_folder}"
                    )
                    continue
                algorithm_output = possible_outputs[0]

                output_file = output_folder / f"{external_name}.nii.gz"
            shutil.move(algorithm_output, output_file)

    def _get_backend_runner(
        self, backend: Optional[Backends]
    ) -> Optional[Callable[..., object]]:
        if backend is None:
            return None
        backend_dispatch = {
            Backends.DOCKER: run_docker_container,
            Backends.SINGULARITY: run_singularity_container,
        }
        runner = backend_dispatch.get(backend)
        return runner

    def _infer_single(
        self,
        inputs: dict[str, Path | str],
        output_file: Path | str,
        log_file: Optional[Path | str] = None,
        backend: Optional[Backends] = Backends.DOCKER,
    ) -> None:
        """
        Perform a single inference run with the provided inputs and save the output
        in the specified file.

        Args:
            inputs (dict[str, Path  |  str]): Input Images for the task
            output_file (Path | str): File to save the output
            log_file (Optional[Path  |  str], optional): Log file with extra
                information. Defaults to None.
            backend (Backends | str, optional): Backend to use for inference.
                Defaults to Backends.DOCKER.
        """
        with InferenceSetup(log_file=log_file) as (tmp_data_folder, tmp_output_folder):
            logger.info("Performing single inference")

            # the id here is arbitrary
            subject_id = self.algorithm.run_args.input_name_schema.format(id=0)

            self._standardize_single_inputs(
                data_folder=tmp_data_folder,
                subject_id=subject_id,
                inputs=inputs,
                subject_modality_separator=self.algorithm.run_args.subject_modality_separator,
            )

            runner = self._get_backend_runner(backend)
            if runner is None:
                raise ValueError(f"Unsupported backend: {backend}")
            runner(
                algorithm=self.algorithm,
                data_path=tmp_data_folder,
                output_path=tmp_output_folder,
                cuda_devices=self.cuda_devices,
                force_cpu=self.force_cpu,
            )
            self._process_single_output(
                tmp_output_folder=tmp_output_folder,
                subject_id=subject_id,
                output_file=Path(output_file),
            )
            logger.info(f"Saved output to: {Path(output_file).absolute()}")

    def _infer_batch(
        self,
        data_folder: Path | str,
        output_folder: Path | str,
        log_file: Optional[Path | str] = None,
        backend: Optional[Backends] = Backends.DOCKER,
    ) -> None:
        """Perform a batch inference run with the provided inputs and save the outputs
        in the specified folder.

        Args:
            data_folder (Path | str): Folder with the input data
            output_folder (Path | str): Folder to save the outputs
            log_file (Optional[Path  |  str], optional): Log file with extra
                information. Defaults to None.
            backend (Backends, optional): Backend to use for inference.
                Defaults to Backends.DOCKER.
        """
        with InferenceSetup(log_file=log_file) as (tmp_data_folder, tmp_output_folder):
            # find subjects
            subjects = [f for f in Path(data_folder).iterdir() if f.is_dir()]
            logger.info(
                f"Found {len(subjects)} subjects: "
                f"{', '.join([s.name for s in subjects][:5])}"
                f"{' ...' if len(subjects) > 5 else ''}"
            )
            # map to brats names
            internal_external_name_map = self._standardize_batch_inputs(
                data_folder=tmp_data_folder,
                subjects=subjects,
                input_name_schema=self.algorithm.run_args.input_name_schema,
            )
            logger.info("Standardized input names to match algorithm requirements.")
            runner = self._get_backend_runner(backend)
            if runner is None:
                raise ValueError(f"Unsupported backend: {backend}")
            # run inference in container
            runner(
                algorithm=self.algorithm,
                data_path=tmp_data_folder,
                output_path=tmp_output_folder,
                cuda_devices=self.cuda_devices,
                force_cpu=self.force_cpu,
                internal_external_name_map=internal_external_name_map,
            )

            self._process_batch_output(
                tmp_output_folder=tmp_output_folder,
                output_folder=Path(output_folder),
                mapping=internal_external_name_map,
            )

            logger.info(f"Saved outputs to: {Path(output_folder).absolute()}")

extract_identifier_from_subject_id

extract_identifier_from_subject_id(subject_id: str) -> str

Extract the index from the subject ID Args: subject_id (str): Subject ID of the input Returns: str: Extracted identifier

Source code in brats/core/brats_algorithm.py
72
73
74
75
76
77
78
79
80
def extract_identifier_from_subject_id(self, subject_id: str) -> str:
    """
    Extract the index from the subject ID
    Args:
        subject_id (str): Subject ID of the input
    Returns:
        str: Extracted identifier
    """
    return "-".join(subject_id.split("-")[-2:])