a b/brats_toolkit/cli.py
1
# -*- coding: utf-8 -*-
2
# Author: Christoph Berger
3
# Script for evaluation and bulk segmentation of Brain Tumor Scans
4
# using the MICCAI BRATS algorithmic repository
5
#
6
# Please refer to README.md and LICENSE.md for further documentation
7
# This software is not certified for clinical use.
8
9
import argparse
10
import pprint
11
import subprocess
12
import sys
13
14
from . import fusionator, preprocessor, segmentor
15
16
17
def list_dockers():
18
    seg = segmentor.Segmentor()
19
    pp = pprint.PrettyPrinter(indent=4)
20
    pp.pprint(seg.config)
21
22
23
def list_docker_ids():
24
    seg = segmentor.Segmentor()
25
    pp = pprint.PrettyPrinter(indent=4)
26
    pp.pprint(seg.config.keys())
27
28
29
def list_docker_gpu():
30
    seg = segmentor.Segmentor()
31
    print("all these images support GPU computations:")
32
    for id in seg.config.keys():
33
        if seg.config[id]["runtime"] == "nvidia":
34
            print(id)
35
36
37
def list_docker_cpu():
38
    seg = segmentor.Segmentor()
39
    print("all these images support CPU computations:")
40
    for id in seg.config.keys():
41
        if seg.config[id]["runtime"] == "runc":
42
            print(id)
43
44
45
def fusion():
46
    parser = argparse.ArgumentParser(
47
        description="Runs the Docker orchestra to fuse segmentations. All inputs have to have equal shape and label values"
48
    )
49
    parser.add_argument(
50
        "-i",
51
        "--input",
52
        required=True,
53
        help="Input directory containing all .nii.gz files to be fused",
54
    )
55
    parser.add_argument(
56
        "-m",
57
        "--method",
58
        required=True,
59
        help="Method for fusion: mav for majority voting, simple for SIMPLE",
60
    )
61
    parser.add_argument(
62
        "-o", "--output", help="Filename for the output in format filename.nii.gz"
63
    )
64
    parser.add_argument(
65
        "-v",
66
        "--verbose",
67
        action="store_true",
68
        help="Verbose mode outputs log info to the command line.",
69
    )
70
    try:
71
        args = parser.parse_args()
72
    except SystemExit as e:
73
        if e.code == 2:
74
            parser.print_help()
75
        sys.exit(e.code)
76
    try:
77
        # runs the segmentation with all the settings wished for by the user
78
        fus = fusionator.Fusionator(verbose=args.verbose)
79
        fus._dirFuse(args.input, method=args.method, outputPath=args.output)
80
    except subprocess.CalledProcessError as e:
81
        # Ignoring errors happening in the Docker Process, otherwise we'd e.g. get error messages on exiting the Docker via CTRL+D.
82
        pass
83
    except Exception as e:
84
        print("ERROR DETAIL: ", e)
85
86
87
def segmentation():
88
    parser = argparse.ArgumentParser(
89
        description="Runs the Docker orchestra to segment and fuse segmentations based on the"
90
        "BraTS algorithmic repository"
91
        "Please keep in mind that some models require Nvidia-Docker to run as"
92
        " they need a supported GPU."
93
    )
94
    parser.add_argument(
95
        "-l",
96
        "--list",
97
        help="List all models available for segmentation.",
98
        action="store_true",
99
    )
100
    parser.add_argument(
101
        "-ll",
102
        "--longlist",
103
        help="List all models available for segmentation with details.",
104
        action="store_true",
105
    )
106
    parser.add_argument(
107
        "-lc", "--cpulist", help="List all models supporting cpus.", action="store_true"
108
    )
109
    parser.add_argument(
110
        "-lg", "--gpulist", help="List all models supporting gpus.", action="store_true"
111
    )
112
    parser.add_argument("-t1", required=True, help="Path to the t1 modality.")
113
    parser.add_argument("-t1c", required=True, help="Path to the t1c modality.")
114
    parser.add_argument("-t2", required=True, help="Path to the t2 modality.")
115
    parser.add_argument("-fla", required=True, help="Path to the fla modality.")
116
    parser.add_argument(
117
        "-d",
118
        "--docker",
119
        required=True,
120
        help="Container ID or method used for fusion. (mav, simple, all). Run brats-orchestra --list to display all options.",
121
    )
122
    parser.add_argument(
123
        "-o", "--output", required=True, help="Path to the desired output file."
124
    )
125
    parser.add_argument(
126
        "-v",
127
        "--verbose",
128
        action="store_true",
129
        help="Verbose mode outputs log info to the command line.",
130
    )
131
    parser.add_argument(
132
        "-c", "--config", help="Add a path to a custom config file for dockers here."
133
    )
134
    parser.add_argument(
135
        "-g",
136
        "--gpu",
137
        action="store_true",
138
        help="Pass this flag if your Docker version already supports the --gpus flag.",
139
    )
140
    parser.add_argument("-gi", "--gpuid", help="Specify the GPU bus ID to be used.")
141
    try:
142
        if "-l" in sys.argv[1:] or "--list" in sys.argv[1:]:
143
            list_docker_ids()
144
            sys.exit(0)
145
        elif "-ll" in sys.argv[1:] or "--longlist" in sys.argv[1:]:
146
            list_dockers()
147
            sys.exit(0)
148
        elif "-lg" in sys.argv[1:] or "--gpulist" in sys.argv[1:]:
149
            list_docker_gpu()
150
            sys.exit(0)
151
        elif "-lc" in sys.argv[1:] or "--cpulist" in sys.argv[1:]:
152
            list_docker_cpu()
153
            sys.exit(0)
154
        else:
155
            args = parser.parse_args()
156
    except SystemExit as e:
157
        if e.code == 2:
158
            parser.print_help()
159
        sys.exit(e.code)
160
    try:
161
        # runs the segmentation with all the settings wished for by the user
162
        seg = segmentor.Segmentor(
163
            config=args.config,
164
            verbose=args.verbose,
165
            newdocker=args.gpu,
166
            gpu=str(args.gpuid),
167
        )
168
        seg.segment(
169
            t1=args.t1,
170
            t1c=args.t1c,
171
            t2=args.t2,
172
            fla=args.fla,
173
            cid=args.docker,
174
            outputPath=args.output,
175
        )
176
    except subprocess.CalledProcessError as e:
177
        # Ignoring errors happening in the Docker Process, otherwise we'd e.g. get error messages on exiting the Docker via CTRL+D.
178
        pass
179
    except Exception as e:
180
        print("ERROR DETAIL: ", e)
181
182
183
def batchpreprocess():
184
    parser = argparse.ArgumentParser(
185
        description="Runs the preprocessing for MRI scans on a folder of images."
186
    )
187
    parser.add_argument(
188
        "-i",
189
        "--input",
190
        required=True,
191
        help="The input directory with 4 modalities in unprocessed Nifti format.",
192
    )
193
    parser.add_argument(
194
        "-o", "--output", required=True, help="Path to the desired output directory."
195
    )
196
    parser.add_argument(
197
        "-s",
198
        "--skipupdate",
199
        action="store_true",
200
        help="If passed, the backend will not be updated.",
201
    )
202
    parser.add_argument(
203
        "-c",
204
        "--confirm",
205
        action="store_true",
206
        help="If passed, the container will ask for confirmation",
207
    )
208
    parser.add_argument(
209
        "-g",
210
        "--gpu",
211
        action="store_true",
212
        help="Pass this flag if you want to use GPU computations.",
213
    )
214
    parser.add_argument("-gi", "--gpuid", help="Specify the GPU bus ID to be used.")
215
    try:
216
        args = parser.parse_args()
217
    except SystemExit as e:
218
        if e.code == 2:
219
            parser.print_help()
220
        sys.exit(e.code)
221
    try:
222
        # runs the preprocessing with all the settings wished for by the user
223
        pre = preprocessor.Preprocessor()
224
        if args.gpu:
225
            mode = "gpu"
226
        else:
227
            mode = "cpu"
228
        if args.gpuid:
229
            gpuid = str(args.gpuid)
230
        else:
231
            gpuid = "0"
232
        pre.batch_preprocess(
233
            exam_import_folder=args.input,
234
            exam_export_folder=args.output,
235
            mode=mode,
236
            confirm=args.confirm,
237
            skipUpdate=args.skipupdate,
238
            gpuid=gpuid,
239
        )
240
    except subprocess.CalledProcessError as e:
241
        # Ignoring errors happening in the Docker Process, otherwise we'd e.g. get error messages on exiting the Docker via CTRL+D.
242
        pass
243
    except Exception as e:
244
        print("ERROR DETAIL: ", e)
245
246
247
def singlepreprocess():
248
    parser = argparse.ArgumentParser(
249
        description="Runs the preprocessing for MRI scans on a single set of images."
250
    )
251
    parser.add_argument("-t1", required=True, help="Path to the t1 modality.")
252
    parser.add_argument("-t1c", required=True, help="Path to the t1c modality.")
253
    parser.add_argument("-t2", required=True, help="Path to the t2 modality.")
254
    parser.add_argument("-fla", required=True, help="Path to the fla modality.")
255
    parser.add_argument(
256
        "-o", "--output", required=True, help="Path to the desired output directory."
257
    )
258
    parser.add_argument(
259
        "-s",
260
        "--skipupdate",
261
        action="store_true",
262
        help="If passed, the backend will not be updated.",
263
    )
264
    parser.add_argument(
265
        "-c",
266
        "--confirm",
267
        action="store_true",
268
        help="If passed, the container will ask for confirmation",
269
    )
270
    parser.add_argument(
271
        "-g",
272
        "--gpu",
273
        action="store_true",
274
        help="Pass this flag if you want to use GPU computations.",
275
    )
276
    parser.add_argument("-gi", "--gpuid", help="Specify the GPU bus ID to be used.")
277
    try:
278
        args = parser.parse_args()
279
    except SystemExit as e:
280
        if e.code == 2:
281
            parser.print_help()
282
        sys.exit(e.code)
283
    try:
284
        # runs the preprocessing with all the settings wished for by the user
285
        pre = preprocessor.Preprocessor()
286
        if args.gpu:
287
            mode = "gpu"
288
        else:
289
            mode = "cpu"
290
        if args.gpuid:
291
            gpuid = str(args.gpuid)
292
        else:
293
            gpuid = "0"
294
        pre.single_preprocess(
295
            t1File=args.t1,
296
            t1cFile=args.t1c,
297
            t2File=args.t2,
298
            flaFile=args.fla,
299
            outputFolder=args.output,
300
            mode=mode,
301
            confirm=args.confirm,
302
            skipUpdate=args.skipupdate,
303
            gpuid=gpuid,
304
        )
305
    except subprocess.CalledProcessError as e:
306
        # Ignoring errors happening in the Docker Process, otherwise we'd e.g. get error messages on exiting the Docker via CTRL+D.
307
        pass
308
    except Exception as e:
309
        print("ERROR DETAIL: ", e)
310
311
312
if __name__ == "__main__":
313
    segmentation()