mosamatic2 2.0.24__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- models.py +259 -0
- mosamatic2/__init__.py +0 -0
- mosamatic2/app.py +32 -0
- mosamatic2/cli.py +50 -0
- mosamatic2/commands/__init__.py +0 -0
- mosamatic2/commands/boadockerpipeline.py +48 -0
- mosamatic2/commands/calculatemaskstatistics.py +59 -0
- mosamatic2/commands/calculatescores.py +73 -0
- mosamatic2/commands/createdicomsummary.py +61 -0
- mosamatic2/commands/createpngsfromsegmentations.py +65 -0
- mosamatic2/commands/defaultdockerpipeline.py +84 -0
- mosamatic2/commands/defaultpipeline.py +70 -0
- mosamatic2/commands/dicom2nifti.py +55 -0
- mosamatic2/commands/liveranalysispipeline.py +61 -0
- mosamatic2/commands/rescaledicomimages.py +54 -0
- mosamatic2/commands/segmentmusclefatl3tensorflow.py +55 -0
- mosamatic2/commands/selectslicefromscans.py +66 -0
- mosamatic2/commands/totalsegmentator.py +77 -0
- mosamatic2/constants.py +27 -0
- mosamatic2/core/__init__.py +0 -0
- mosamatic2/core/data/__init__.py +5 -0
- mosamatic2/core/data/dicomimage.py +27 -0
- mosamatic2/core/data/dicomimageseries.py +26 -0
- mosamatic2/core/data/dixonseries.py +22 -0
- mosamatic2/core/data/filedata.py +26 -0
- mosamatic2/core/data/multidicomimage.py +30 -0
- mosamatic2/core/data/multiniftiimage.py +26 -0
- mosamatic2/core/data/multinumpyimage.py +26 -0
- mosamatic2/core/data/niftiimage.py +13 -0
- mosamatic2/core/data/numpyimage.py +13 -0
- mosamatic2/core/managers/__init__.py +0 -0
- mosamatic2/core/managers/logmanager.py +45 -0
- mosamatic2/core/managers/logmanagerlistener.py +3 -0
- mosamatic2/core/pipelines/__init__.py +4 -0
- mosamatic2/core/pipelines/boadockerpipeline/__init__.py +0 -0
- mosamatic2/core/pipelines/boadockerpipeline/boadockerpipeline.py +70 -0
- mosamatic2/core/pipelines/defaultdockerpipeline/__init__.py +0 -0
- mosamatic2/core/pipelines/defaultdockerpipeline/defaultdockerpipeline.py +28 -0
- mosamatic2/core/pipelines/defaultpipeline/__init__.py +0 -0
- mosamatic2/core/pipelines/defaultpipeline/defaultpipeline.py +90 -0
- mosamatic2/core/pipelines/liveranalysispipeline/__init__.py +0 -0
- mosamatic2/core/pipelines/liveranalysispipeline/liveranalysispipeline.py +48 -0
- mosamatic2/core/pipelines/pipeline.py +14 -0
- mosamatic2/core/singleton.py +9 -0
- mosamatic2/core/tasks/__init__.py +13 -0
- mosamatic2/core/tasks/applythresholdtosegmentationstask/__init__.py +0 -0
- mosamatic2/core/tasks/applythresholdtosegmentationstask/applythresholdtosegmentationstask.py +117 -0
- mosamatic2/core/tasks/calculatemaskstatisticstask/__init__.py +0 -0
- mosamatic2/core/tasks/calculatemaskstatisticstask/calculatemaskstatisticstask.py +104 -0
- mosamatic2/core/tasks/calculatescorestask/__init__.py +0 -0
- mosamatic2/core/tasks/calculatescorestask/calculatescorestask.py +152 -0
- mosamatic2/core/tasks/createdicomsummarytask/__init__.py +0 -0
- mosamatic2/core/tasks/createdicomsummarytask/createdicomsummarytask.py +88 -0
- mosamatic2/core/tasks/createpngsfromsegmentationstask/__init__.py +0 -0
- mosamatic2/core/tasks/createpngsfromsegmentationstask/createpngsfromsegmentationstask.py +101 -0
- mosamatic2/core/tasks/dicom2niftitask/__init__.py +0 -0
- mosamatic2/core/tasks/dicom2niftitask/dicom2niftitask.py +45 -0
- mosamatic2/core/tasks/rescaledicomimagestask/__init__.py +0 -0
- mosamatic2/core/tasks/rescaledicomimagestask/rescaledicomimagestask.py +64 -0
- mosamatic2/core/tasks/segmentationnifti2numpytask/__init__.py +0 -0
- mosamatic2/core/tasks/segmentationnifti2numpytask/segmentationnifti2numpytask.py +57 -0
- mosamatic2/core/tasks/segmentationnumpy2niftitask/__init__.py +0 -0
- mosamatic2/core/tasks/segmentationnumpy2niftitask/segmentationnumpy2niftitask.py +86 -0
- mosamatic2/core/tasks/segmentmusclefatl3tensorflowtask/__init__.py +0 -0
- mosamatic2/core/tasks/segmentmusclefatl3tensorflowtask/paramloader.py +39 -0
- mosamatic2/core/tasks/segmentmusclefatl3tensorflowtask/segmentmusclefatl3tensorflowtask.py +122 -0
- mosamatic2/core/tasks/segmentmusclefatt4pytorchtask/__init__.py +0 -0
- mosamatic2/core/tasks/segmentmusclefatt4pytorchtask/paramloader.py +39 -0
- mosamatic2/core/tasks/segmentmusclefatt4pytorchtask/segmentmusclefatt4pytorchtask.py +128 -0
- mosamatic2/core/tasks/selectslicefromscanstask/__init__.py +0 -0
- mosamatic2/core/tasks/selectslicefromscanstask/selectslicefromscanstask.py +249 -0
- mosamatic2/core/tasks/task.py +50 -0
- mosamatic2/core/tasks/totalsegmentatortask/__init__.py +0 -0
- mosamatic2/core/tasks/totalsegmentatortask/totalsegmentatortask.py +75 -0
- mosamatic2/core/utils.py +405 -0
- mosamatic2/server.py +146 -0
- mosamatic2/ui/__init__.py +0 -0
- mosamatic2/ui/mainwindow.py +426 -0
- mosamatic2/ui/resources/VERSION +1 -0
- mosamatic2/ui/resources/icons/mosamatic2.icns +0 -0
- mosamatic2/ui/resources/icons/mosamatic2.ico +0 -0
- mosamatic2/ui/resources/icons/spinner.gif +0 -0
- mosamatic2/ui/resources/images/body-composition.jpg +0 -0
- mosamatic2/ui/settings.py +62 -0
- mosamatic2/ui/utils.py +36 -0
- mosamatic2/ui/widgets/__init__.py +0 -0
- mosamatic2/ui/widgets/dialogs/__init__.py +0 -0
- mosamatic2/ui/widgets/dialogs/dialog.py +16 -0
- mosamatic2/ui/widgets/dialogs/helpdialog.py +9 -0
- mosamatic2/ui/widgets/panels/__init__.py +0 -0
- mosamatic2/ui/widgets/panels/defaultpanel.py +31 -0
- mosamatic2/ui/widgets/panels/logpanel.py +65 -0
- mosamatic2/ui/widgets/panels/mainpanel.py +82 -0
- mosamatic2/ui/widgets/panels/pipelines/__init__.py +0 -0
- mosamatic2/ui/widgets/panels/pipelines/boadockerpipelinepanel.py +195 -0
- mosamatic2/ui/widgets/panels/pipelines/defaultdockerpipelinepanel.py +314 -0
- mosamatic2/ui/widgets/panels/pipelines/defaultpipelinepanel.py +302 -0
- mosamatic2/ui/widgets/panels/pipelines/liveranalysispipelinepanel.py +187 -0
- mosamatic2/ui/widgets/panels/pipelines/pipelinepanel.py +6 -0
- mosamatic2/ui/widgets/panels/settingspanel.py +16 -0
- mosamatic2/ui/widgets/panels/stackedpanel.py +22 -0
- mosamatic2/ui/widgets/panels/tasks/__init__.py +0 -0
- mosamatic2/ui/widgets/panels/tasks/applythresholdtosegmentationstaskpanel.py +271 -0
- mosamatic2/ui/widgets/panels/tasks/calculatemaskstatisticstaskpanel.py +215 -0
- mosamatic2/ui/widgets/panels/tasks/calculatescorestaskpanel.py +238 -0
- mosamatic2/ui/widgets/panels/tasks/createdicomsummarytaskpanel.py +206 -0
- mosamatic2/ui/widgets/panels/tasks/createpngsfromsegmentationstaskpanel.py +247 -0
- mosamatic2/ui/widgets/panels/tasks/dicom2niftitaskpanel.py +183 -0
- mosamatic2/ui/widgets/panels/tasks/rescaledicomimagestaskpanel.py +184 -0
- mosamatic2/ui/widgets/panels/tasks/segmentationnifti2numpytaskpanel.py +192 -0
- mosamatic2/ui/widgets/panels/tasks/segmentationnumpy2niftitaskpanel.py +213 -0
- mosamatic2/ui/widgets/panels/tasks/segmentmusclefatl3tensorflowtaskpanel.py +216 -0
- mosamatic2/ui/widgets/panels/tasks/segmentmusclefatt4pytorchtaskpanel.py +217 -0
- mosamatic2/ui/widgets/panels/tasks/selectslicefromscanstaskpanel.py +193 -0
- mosamatic2/ui/widgets/panels/tasks/taskpanel.py +6 -0
- mosamatic2/ui/widgets/panels/tasks/totalsegmentatortaskpanel.py +195 -0
- mosamatic2/ui/widgets/panels/visualizations/__init__.py +0 -0
- mosamatic2/ui/widgets/panels/visualizations/liversegmentvisualization/__init__.py +0 -0
- mosamatic2/ui/widgets/panels/visualizations/liversegmentvisualization/liversegmentpicker.py +96 -0
- mosamatic2/ui/widgets/panels/visualizations/liversegmentvisualization/liversegmentviewer.py +130 -0
- mosamatic2/ui/widgets/panels/visualizations/liversegmentvisualization/liversegmentvisualization.py +120 -0
- mosamatic2/ui/widgets/panels/visualizations/sliceselectionvisualization/__init__.py +0 -0
- mosamatic2/ui/widgets/panels/visualizations/sliceselectionvisualization/sliceselectionviewer.py +61 -0
- mosamatic2/ui/widgets/panels/visualizations/sliceselectionvisualization/sliceselectionvisualization.py +133 -0
- mosamatic2/ui/widgets/panels/visualizations/sliceselectionvisualization/slicetile.py +63 -0
- mosamatic2/ui/widgets/panels/visualizations/slicevisualization/__init__.py +0 -0
- mosamatic2/ui/widgets/panels/visualizations/slicevisualization/custominteractorstyle.py +80 -0
- mosamatic2/ui/widgets/panels/visualizations/slicevisualization/sliceviewer.py +116 -0
- mosamatic2/ui/widgets/panels/visualizations/slicevisualization/slicevisualization.py +141 -0
- mosamatic2/ui/widgets/panels/visualizations/visualization.py +6 -0
- mosamatic2/ui/widgets/splashscreen.py +101 -0
- mosamatic2/ui/worker.py +29 -0
- mosamatic2-2.0.24.dist-info/METADATA +43 -0
- mosamatic2-2.0.24.dist-info/RECORD +136 -0
- mosamatic2-2.0.24.dist-info/WHEEL +4 -0
- mosamatic2-2.0.24.dist-info/entry_points.txt +5 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import click
|
|
2
|
+
|
|
3
|
+
from mosamatic2.core.pipelines import DefaultDockerPipeline
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@click.command(help='Runs default L3 analysis pipeline through Docker')
|
|
7
|
+
@click.option(
|
|
8
|
+
'--images',
|
|
9
|
+
required=True,
|
|
10
|
+
type=click.Path(exists=True),
|
|
11
|
+
help='Directory with L3 images (no spaces allowed)',
|
|
12
|
+
)
|
|
13
|
+
@click.option(
|
|
14
|
+
'--model_files',
|
|
15
|
+
required=True,
|
|
16
|
+
type=click.Path(),
|
|
17
|
+
help='Input directory with AI model files (no spaces allowed)'
|
|
18
|
+
)
|
|
19
|
+
@click.option(
|
|
20
|
+
'--version',
|
|
21
|
+
required=True,
|
|
22
|
+
help='Docker image version'
|
|
23
|
+
)
|
|
24
|
+
@click.option(
|
|
25
|
+
'--output',
|
|
26
|
+
required=True,
|
|
27
|
+
type=click.Path(),
|
|
28
|
+
help='Output directory (no spaces allowed)'
|
|
29
|
+
)
|
|
30
|
+
@click.option(
|
|
31
|
+
'--overwrite',
|
|
32
|
+
type=click.BOOL,
|
|
33
|
+
default=False,
|
|
34
|
+
help='Overwrite [true|false]'
|
|
35
|
+
)
|
|
36
|
+
def defaultdockerpipeline(images, model_files, version, output, overwrite):
|
|
37
|
+
"""
|
|
38
|
+
Runs default L3 analysis pipeline through Docker
|
|
39
|
+
|
|
40
|
+
Parameters
|
|
41
|
+
----------
|
|
42
|
+
--images : str
|
|
43
|
+
Directory with L3 images. Warning: This directory path cannot contain any spaces!
|
|
44
|
+
Docker has issues working with that.
|
|
45
|
+
|
|
46
|
+
--model_files : str
|
|
47
|
+
Directory with AI model files. This directory can ONLY contain the following
|
|
48
|
+
files:
|
|
49
|
+
|
|
50
|
+
(1) contour_model-1.0.zip
|
|
51
|
+
(2) model-1.0.zip
|
|
52
|
+
(3) params-1.0.json
|
|
53
|
+
|
|
54
|
+
These files can be downloaded from:
|
|
55
|
+
https://mosamatic.rbeesoft.nl/wordpress/mosamatic/installation/
|
|
56
|
+
|
|
57
|
+
Warning: This directory path cannot contain any spaces!
|
|
58
|
+
|
|
59
|
+
--version : str
|
|
60
|
+
Docker image version, e.g., 2.0.16
|
|
61
|
+
Check https://hub.docker.com/repository/docker/brecheisen/mosamatic2-cli/general
|
|
62
|
+
for the latest version and older versions.
|
|
63
|
+
|
|
64
|
+
--output : str
|
|
65
|
+
Path to output directory (no spaces!)
|
|
66
|
+
|
|
67
|
+
--overwrite : bool
|
|
68
|
+
Overwrite contents output directory [true|false]
|
|
69
|
+
"""
|
|
70
|
+
pipeline = DefaultDockerPipeline(
|
|
71
|
+
inputs={'images': images, 'model_files': model_files},
|
|
72
|
+
params={
|
|
73
|
+
'target_size': 512,
|
|
74
|
+
'model_type': 'tensorflow',
|
|
75
|
+
'model_version': 1.0,
|
|
76
|
+
'file_type': 'npy',
|
|
77
|
+
'fig_width': 10,
|
|
78
|
+
'fig_height': 10,
|
|
79
|
+
'version': version,
|
|
80
|
+
},
|
|
81
|
+
output=output,
|
|
82
|
+
overwrite=overwrite,
|
|
83
|
+
)
|
|
84
|
+
pipeline.run()
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import click
|
|
2
|
+
|
|
3
|
+
from mosamatic2.core.pipelines import DefaultPipeline
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@click.command(help='Runs default L3 analysis pipeline')
|
|
7
|
+
@click.option(
|
|
8
|
+
'--images',
|
|
9
|
+
required=True,
|
|
10
|
+
type=click.Path(exists=True),
|
|
11
|
+
help='Directory with L3 images',
|
|
12
|
+
)
|
|
13
|
+
@click.option(
|
|
14
|
+
'--model_files',
|
|
15
|
+
required=True,
|
|
16
|
+
type=click.Path(),
|
|
17
|
+
help='Input directory with AI model files'
|
|
18
|
+
)
|
|
19
|
+
@click.option(
|
|
20
|
+
'--output',
|
|
21
|
+
required=True,
|
|
22
|
+
type=click.Path(),
|
|
23
|
+
help='Output directory'
|
|
24
|
+
)
|
|
25
|
+
@click.option(
|
|
26
|
+
'--overwrite',
|
|
27
|
+
type=click.BOOL,
|
|
28
|
+
default=False,
|
|
29
|
+
help='Overwrite [true|false]'
|
|
30
|
+
)
|
|
31
|
+
def defaultpipeline(images, model_files, output, overwrite):
|
|
32
|
+
"""
|
|
33
|
+
Runs default L3 analysis pipeline
|
|
34
|
+
|
|
35
|
+
Parameters
|
|
36
|
+
----------
|
|
37
|
+
--images : str
|
|
38
|
+
Directory with L3 images
|
|
39
|
+
|
|
40
|
+
--model_files : str
|
|
41
|
+
Directory with AI model files. This directory can ONLY contain the following
|
|
42
|
+
files:
|
|
43
|
+
|
|
44
|
+
(1) contour_model-1.0.zip
|
|
45
|
+
(2) model-1.0.zip
|
|
46
|
+
(3) params-1.0.json
|
|
47
|
+
|
|
48
|
+
These files can be downloaded from:
|
|
49
|
+
https://mosamatic.rbeesoft.nl/wordpress/mosamatic/installation/
|
|
50
|
+
|
|
51
|
+
--output : str
|
|
52
|
+
Path to output directory
|
|
53
|
+
|
|
54
|
+
--overwrite : bool
|
|
55
|
+
Overwrite contents output directory [true|false]
|
|
56
|
+
"""
|
|
57
|
+
pipeline = DefaultPipeline(
|
|
58
|
+
inputs={'images': images, 'model_files': model_files},
|
|
59
|
+
params={
|
|
60
|
+
'target_size': 512,
|
|
61
|
+
'model_type': 'tensorflow',
|
|
62
|
+
'model_version': 1.0,
|
|
63
|
+
'file_type': 'npy',
|
|
64
|
+
'fig_width': 10,
|
|
65
|
+
'fig_height': 10,
|
|
66
|
+
},
|
|
67
|
+
output=output,
|
|
68
|
+
overwrite=overwrite,
|
|
69
|
+
)
|
|
70
|
+
pipeline.run()
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import click
|
|
2
|
+
|
|
3
|
+
from mosamatic2.core.tasks import Dicom2NiftiTask
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@click.command(help='Converts root directory with DICOM series to NIFTI format')
|
|
7
|
+
@click.option(
|
|
8
|
+
'--scans',
|
|
9
|
+
required=True,
|
|
10
|
+
type=click.Path(exists=True),
|
|
11
|
+
help='Root directory with DICOM scans (one for each patient)',
|
|
12
|
+
)
|
|
13
|
+
@click.option(
|
|
14
|
+
'--compressed',
|
|
15
|
+
type=click.BOOL,
|
|
16
|
+
default=True,
|
|
17
|
+
help='Compress with gzip [true|false] (default: True)'
|
|
18
|
+
)
|
|
19
|
+
@click.option(
|
|
20
|
+
'--output',
|
|
21
|
+
required=True,
|
|
22
|
+
type=click.Path(),
|
|
23
|
+
help='Output directory'
|
|
24
|
+
)
|
|
25
|
+
@click.option(
|
|
26
|
+
'--overwrite',
|
|
27
|
+
type=click.BOOL,
|
|
28
|
+
default=False,
|
|
29
|
+
help='Overwrite [true|false]'
|
|
30
|
+
)
|
|
31
|
+
def dicom2nifti(scans, compressed, output, overwrite):
|
|
32
|
+
"""
|
|
33
|
+
Converts DICOM scans to NIFTI format.
|
|
34
|
+
|
|
35
|
+
Parameters
|
|
36
|
+
----------
|
|
37
|
+
--scans : str
|
|
38
|
+
Root directory with DICOM scans (one subdirectory for each patient)
|
|
39
|
+
|
|
40
|
+
--compressed : bool
|
|
41
|
+
Whether to compress the NIFTI file with gzip or not (default: True)
|
|
42
|
+
|
|
43
|
+
--output : str
|
|
44
|
+
Path to output directory
|
|
45
|
+
|
|
46
|
+
--overwrite : bool
|
|
47
|
+
Overwrite contents output directory [true|false]
|
|
48
|
+
"""
|
|
49
|
+
task = Dicom2NiftiTask(
|
|
50
|
+
inputs={'scans': scans},
|
|
51
|
+
params={'compressed': compressed},
|
|
52
|
+
output=output,
|
|
53
|
+
overwrite=overwrite,
|
|
54
|
+
)
|
|
55
|
+
task.run()
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import click
|
|
2
|
+
|
|
3
|
+
from mosamatic2.core.pipelines import LiverAnalysisPipeline
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@click.command(help='Runs liver analysis pipeline')
|
|
7
|
+
@click.option(
|
|
8
|
+
'--scans',
|
|
9
|
+
required=True,
|
|
10
|
+
type=click.Path(exists=True),
|
|
11
|
+
help='Root directory with scan directories for each patient (no spaces allowed)',
|
|
12
|
+
)
|
|
13
|
+
@click.option(
|
|
14
|
+
'--compressed',
|
|
15
|
+
default=True,
|
|
16
|
+
help='Whether to produce compressed NIFTI file or not (default: True)'
|
|
17
|
+
)
|
|
18
|
+
@click.option(
|
|
19
|
+
'--output',
|
|
20
|
+
required=True,
|
|
21
|
+
type=click.Path(),
|
|
22
|
+
help='Output directory (no spaces allowed)'
|
|
23
|
+
)
|
|
24
|
+
@click.option(
|
|
25
|
+
'--overwrite',
|
|
26
|
+
type=click.BOOL,
|
|
27
|
+
default=False,
|
|
28
|
+
help='Overwrite [true|false]'
|
|
29
|
+
)
|
|
30
|
+
def liveranalysispipeline(scans, compressed, output, overwrite):
|
|
31
|
+
"""
|
|
32
|
+
Runs liver analysis pipeline. This pipeline run the following steps on each scan:
|
|
33
|
+
|
|
34
|
+
(1) DICOM to NIFTI conversion
|
|
35
|
+
(2) Extract liver segments using Total Segmentator
|
|
36
|
+
(3) Calculate segment statistics, e.g., volume (mL), mean HU, std HU and PNG image
|
|
37
|
+
of each segments HU histogram.
|
|
38
|
+
|
|
39
|
+
Parameters
|
|
40
|
+
----------
|
|
41
|
+
--scans : str
|
|
42
|
+
Root directory with scan directories for each patient. Each scan directory should
|
|
43
|
+
contain DICOM images for a single scan only and nothing else. Also, the directory
|
|
44
|
+
paths cannot contain any spaces.
|
|
45
|
+
|
|
46
|
+
--compressed : str
|
|
47
|
+
Whether to produce compressed NIFTI file or not (default: True)
|
|
48
|
+
|
|
49
|
+
--output : str
|
|
50
|
+
Path to output directory. No spaces allowed.
|
|
51
|
+
|
|
52
|
+
--overwrite : bool
|
|
53
|
+
Overwrite contents output directory [true|false]
|
|
54
|
+
"""
|
|
55
|
+
pipeline = LiverAnalysisPipeline(
|
|
56
|
+
inputs={'scans': scans},
|
|
57
|
+
params={'compressed': compressed},
|
|
58
|
+
output=output,
|
|
59
|
+
overwrite=overwrite,
|
|
60
|
+
)
|
|
61
|
+
pipeline.run()
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import click
|
|
2
|
+
|
|
3
|
+
from mosamatic2.core.tasks import RescaleDicomImagesTask
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@click.command(help='Rescale DICOM files to target size')
|
|
7
|
+
@click.option(
|
|
8
|
+
'--images',
|
|
9
|
+
required=True,
|
|
10
|
+
type=click.Path(exists=True),
|
|
11
|
+
help='Input directory with images'
|
|
12
|
+
)
|
|
13
|
+
@click.option(
|
|
14
|
+
'--output',
|
|
15
|
+
required=True,
|
|
16
|
+
type=click.Path(),
|
|
17
|
+
help='Output directory'
|
|
18
|
+
)
|
|
19
|
+
@click.option(
|
|
20
|
+
'--target_size',
|
|
21
|
+
default=512,
|
|
22
|
+
help='Target size of rescaled images (default: 512)'
|
|
23
|
+
)
|
|
24
|
+
@click.option(
|
|
25
|
+
'--overwrite',
|
|
26
|
+
type=click.BOOL,
|
|
27
|
+
default=False,
|
|
28
|
+
help='Overwrite [true|false]'
|
|
29
|
+
)
|
|
30
|
+
def rescaledicomimages(images, output, target_size, overwrite):
|
|
31
|
+
"""
|
|
32
|
+
Rescales DICOM images to given (square) target size
|
|
33
|
+
|
|
34
|
+
Parameters
|
|
35
|
+
----------
|
|
36
|
+
--images : str
|
|
37
|
+
Directory with input DICOM images
|
|
38
|
+
|
|
39
|
+
--output : str
|
|
40
|
+
Path to output directory
|
|
41
|
+
|
|
42
|
+
--target_size : int
|
|
43
|
+
Target size for rescaled images (default: 512)
|
|
44
|
+
|
|
45
|
+
--overwrite : bool
|
|
46
|
+
Overwrite contents output directory: [true|false]
|
|
47
|
+
"""
|
|
48
|
+
task = RescaleDicomImagesTask(
|
|
49
|
+
inputs={'images': images},
|
|
50
|
+
params={'target_size': target_size},
|
|
51
|
+
output=output,
|
|
52
|
+
overwrite=overwrite
|
|
53
|
+
)
|
|
54
|
+
task.run()
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import click
|
|
2
|
+
|
|
3
|
+
from mosamatic2.core.tasks import SegmentMuscleFatL3TensorFlowTask
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@click.command(help='Extracts muscle and fat regions from CT images at L3 (uses PyTorch)')
|
|
7
|
+
@click.option(
|
|
8
|
+
'--images',
|
|
9
|
+
required=True,
|
|
10
|
+
type=click.Path(),
|
|
11
|
+
help='Input directory with images'
|
|
12
|
+
)
|
|
13
|
+
@click.option(
|
|
14
|
+
'--model_files',
|
|
15
|
+
required=True,
|
|
16
|
+
type=click.Path(),
|
|
17
|
+
help='Input directory with AI model files'
|
|
18
|
+
)
|
|
19
|
+
@click.option(
|
|
20
|
+
'--output',
|
|
21
|
+
required=True,
|
|
22
|
+
type=click.Path(),
|
|
23
|
+
help='Output directory'
|
|
24
|
+
)
|
|
25
|
+
@click.option(
|
|
26
|
+
'--overwrite',
|
|
27
|
+
default=False,
|
|
28
|
+
type=click.BOOL,
|
|
29
|
+
help='Overwrite [true|false]'
|
|
30
|
+
)
|
|
31
|
+
def segmentmusclefatl3tensorflow(images, model_files, output, overwrite):
|
|
32
|
+
"""
|
|
33
|
+
Automatically segments muscle and fat tissue in CT images at L3 level.
|
|
34
|
+
|
|
35
|
+
Parameters
|
|
36
|
+
----------
|
|
37
|
+
--images : str
|
|
38
|
+
Directory with input L3 images
|
|
39
|
+
|
|
40
|
+
--model_files : str
|
|
41
|
+
Directory with AI model files (model-1.0.zip, contour_model-1.0.zip, params-1.0.json)
|
|
42
|
+
|
|
43
|
+
--output : str
|
|
44
|
+
Path to output directory
|
|
45
|
+
|
|
46
|
+
--overwrite : bool
|
|
47
|
+
Overwrite contents output directory [true|false]
|
|
48
|
+
"""
|
|
49
|
+
task = SegmentMuscleFatL3TensorFlowTask(
|
|
50
|
+
inputs={'images': images, 'model_files': model_files},
|
|
51
|
+
params={'model_version': 1.0},
|
|
52
|
+
output=output,
|
|
53
|
+
overwrite=overwrite,
|
|
54
|
+
)
|
|
55
|
+
task.run()
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import click
|
|
2
|
+
|
|
3
|
+
from mosamatic2.core.tasks import SelectSliceFromScansTask
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@click.command(help='Selects specific slice from CT scans')
|
|
7
|
+
@click.option(
|
|
8
|
+
'--scans',
|
|
9
|
+
required=True,
|
|
10
|
+
type=click.Path(exists=True),
|
|
11
|
+
help='Directory with scans (each patient separate subdirectory)',
|
|
12
|
+
)
|
|
13
|
+
@click.option(
|
|
14
|
+
'--output',
|
|
15
|
+
required=True,
|
|
16
|
+
type=click.Path(),
|
|
17
|
+
help='Output directory'
|
|
18
|
+
)
|
|
19
|
+
@click.option(
|
|
20
|
+
'--vertebra',
|
|
21
|
+
required=True,
|
|
22
|
+
default='L3',
|
|
23
|
+
help='Vertebral level for selecting slice (default: "L3")'
|
|
24
|
+
)
|
|
25
|
+
@click.option(
|
|
26
|
+
'--overwrite',
|
|
27
|
+
type=click.BOOL,
|
|
28
|
+
default=True,
|
|
29
|
+
help='Overwrite [true|false] (default: true)'
|
|
30
|
+
)
|
|
31
|
+
def selectslicefromscans(scans, vertebra, output, overwrite):
|
|
32
|
+
"""
|
|
33
|
+
Selects specific slice from list of CT scans
|
|
34
|
+
|
|
35
|
+
Parameters
|
|
36
|
+
----------
|
|
37
|
+
--scans : str
|
|
38
|
+
Directory to scans. Each patient's scan should be in a separate
|
|
39
|
+
subdirectory. For example:
|
|
40
|
+
|
|
41
|
+
/scans
|
|
42
|
+
/scans/patient1
|
|
43
|
+
/scans/patient1/file1.dcm
|
|
44
|
+
/scans/patient1/file2.dcm
|
|
45
|
+
...
|
|
46
|
+
/scans/patient2
|
|
47
|
+
...
|
|
48
|
+
|
|
49
|
+
--output : str
|
|
50
|
+
Path to output directory where selected slices will be placed. Each
|
|
51
|
+
slice's file name will be the same as the scan directory name, so in
|
|
52
|
+
the example above that would be "patient1", "patient2", etc.
|
|
53
|
+
|
|
54
|
+
--vertebra : str
|
|
55
|
+
Vertebral level where to take slice [L3|T4] (default: L3)
|
|
56
|
+
|
|
57
|
+
--overwrite : bool
|
|
58
|
+
Overwrite contents output directory [true|false] (default: true)
|
|
59
|
+
"""
|
|
60
|
+
task = SelectSliceFromScansTask(
|
|
61
|
+
inputs={'scans': scans},
|
|
62
|
+
params={'vertebra': vertebra},
|
|
63
|
+
output=output,
|
|
64
|
+
overwrite=overwrite,
|
|
65
|
+
)
|
|
66
|
+
task.run()
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import click
|
|
2
|
+
|
|
3
|
+
from mosamatic2.core.tasks import TotalSegmentatorTask
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@click.command(help='Run Total Segmentator on CT scans')
|
|
7
|
+
@click.option(
|
|
8
|
+
'--scans',
|
|
9
|
+
required=True,
|
|
10
|
+
type=click.Path(exists=True),
|
|
11
|
+
help='Directory with scans (each patient separate subdirectory)',
|
|
12
|
+
)
|
|
13
|
+
@click.option(
|
|
14
|
+
'--output',
|
|
15
|
+
required=True,
|
|
16
|
+
type=click.Path(),
|
|
17
|
+
help='Output directory'
|
|
18
|
+
)
|
|
19
|
+
@click.option(
|
|
20
|
+
'--tasks',
|
|
21
|
+
default='total',
|
|
22
|
+
help='Comma-separated list of Total Segmentator tasks to run (no spaces!)'
|
|
23
|
+
)
|
|
24
|
+
@click.option(
|
|
25
|
+
'--format',
|
|
26
|
+
default='dicom',
|
|
27
|
+
help='Process scans in DICOM or NIFTI format [dicom|nifti] (default: dicom)'
|
|
28
|
+
)
|
|
29
|
+
@click.option(
|
|
30
|
+
'--overwrite',
|
|
31
|
+
type=click.BOOL,
|
|
32
|
+
default=False,
|
|
33
|
+
help='Overwrite [true|false]'
|
|
34
|
+
)
|
|
35
|
+
def totalsegmentator(scans, tasks, format, output, overwrite):
|
|
36
|
+
"""
|
|
37
|
+
Run Total Segmentator on CT scans. If you want to run specialized tasks
|
|
38
|
+
like "liver_segments" or "liver_vessels" you need an educational license.
|
|
39
|
+
Check out https://github.com/wasserth/TotalSegmentator?tab=readme-ov-file
|
|
40
|
+
to find out how to get such a license.
|
|
41
|
+
|
|
42
|
+
Parameters
|
|
43
|
+
----------
|
|
44
|
+
--scans : str
|
|
45
|
+
Directory to scans. Each patient's scan should be in a separate
|
|
46
|
+
subdirectory. For example:
|
|
47
|
+
|
|
48
|
+
/scans
|
|
49
|
+
/scans/patient1
|
|
50
|
+
/scans/patient1/file1.dcm
|
|
51
|
+
/scans/patient1/file2.dcm
|
|
52
|
+
...
|
|
53
|
+
/scans/patient2
|
|
54
|
+
...
|
|
55
|
+
|
|
56
|
+
--output : str
|
|
57
|
+
Path to output directory where selected slices will be placed. Each
|
|
58
|
+
slice's file name will be the same as the scan directory name, so in
|
|
59
|
+
the example above that would be "patient1", "patient2", etc.
|
|
60
|
+
|
|
61
|
+
--tasks : str
|
|
62
|
+
Comma-separated list of Total Segmentator tasks to run (no spaces!)
|
|
63
|
+
|
|
64
|
+
--format : str
|
|
65
|
+
Process scans in DICOM or NIFTI format. Options: [dicom|nifti]
|
|
66
|
+
Default is 'dicom'.
|
|
67
|
+
|
|
68
|
+
--overwrite : bool
|
|
69
|
+
Overwrite contents output directory [true|false]
|
|
70
|
+
"""
|
|
71
|
+
task = TotalSegmentatorTask(
|
|
72
|
+
inputs={'scans': scans},
|
|
73
|
+
params={'tasks': tasks, 'format': format},
|
|
74
|
+
output=output,
|
|
75
|
+
overwrite=overwrite,
|
|
76
|
+
)
|
|
77
|
+
task.run()
|
mosamatic2/constants.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
MOSAMATIC2_BUNDLE_IDENTIFIER = 'org.mumc'
|
|
2
|
+
MOSAMATIC2_APP_NAME = 'mosamatic2'
|
|
3
|
+
MOSAMATIC2_VERSION_FILE = 'mosamatic2/ui/resources/VERSION'
|
|
4
|
+
MOSAMATIC2_IMAGES_DIR_PATH = 'mosamatic2/ui/resources/images'
|
|
5
|
+
MOSAMATIC2_ICONS_DIR_PATH = 'mosamatic2/ui/resources/icons'
|
|
6
|
+
MOSAMATIC2_APP_ICON_FILE_NAME_WIN = 'mosamatic2.ico'
|
|
7
|
+
MOSAMATIC2_APP_ICON_FILE_NAME_MAC = 'mosamatic2.icns'
|
|
8
|
+
MOSAMATIC2_BACKGROUND_IMAGE_FILE_NAME = 'body-composition.jpg'
|
|
9
|
+
MOSAMATIC2_BACKGROUND_IMAGE_OPACITY = 0.4
|
|
10
|
+
|
|
11
|
+
MOSAMATIC2_SERVER_PORT = 8000
|
|
12
|
+
MOSAMATIC2_SERVER_DEBUG = True
|
|
13
|
+
|
|
14
|
+
MOSAMATIC2_WINDOW_TITLE = 'Mosamatic'
|
|
15
|
+
MOSAMATIC2_WINDOW_W = 1000
|
|
16
|
+
MOSAMATIC2_WINDOW_H = 600
|
|
17
|
+
MOSAMATIC2_WINDOW_GEOMETRY_KEY = 'mainwindow/geometry'
|
|
18
|
+
MOSAMATIC2_WINDOW_STATE_KEY = 'mainwindow/state'
|
|
19
|
+
|
|
20
|
+
MOSAMATIC2_SPLASH_SCREEN_TITLE = MOSAMATIC2_WINDOW_TITLE
|
|
21
|
+
MOSAMATIC2_SPLASH_SCREEN_TITLE_STYLESHEET = 'color: rgb(64, 64, 64); font-weight: bold; font-size: 32pt;'
|
|
22
|
+
MOSAMATIC2_SPLASH_SCREEN_SUB_TEXT = 'This software is for research only'
|
|
23
|
+
MOSAMATIC2_SPLASH_SCREEN_SUB_TEXT_STYLE_SHEET = 'color: rgb(64, 64, 64); font-style: italic; font-size: 10pt;'
|
|
24
|
+
MOSAMATIC2_SPLASH_SCREEN_START_BUTTON_TEXT = 'Start Application'
|
|
25
|
+
MOSAMATIC2_SPLASH_SCREEN_QUIT_BUTTON_TEXT = 'Quit'
|
|
26
|
+
MOSAMATIC2_SPLASH_SCREEN_W = 600
|
|
27
|
+
MOSAMATIC2_SPLASH_SCREEN_H = 300
|
|
File without changes
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
from mosamatic2.core.data.filedata import FileData
|
|
2
|
+
from mosamatic2.core.data.dicomimage import DicomImage
|
|
3
|
+
from mosamatic2.core.data.dicomimageseries import DicomImageSeries
|
|
4
|
+
from mosamatic2.core.data.multidicomimage import MultiDicomImage
|
|
5
|
+
from mosamatic2.core.data.dixonseries import DixonSeries
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from mosamatic2.core.data.filedata import FileData
|
|
2
|
+
from mosamatic2.core.utils import (
|
|
3
|
+
is_dicom,
|
|
4
|
+
load_dicom,
|
|
5
|
+
is_jpeg2000_compressed,
|
|
6
|
+
)
|
|
7
|
+
from mosamatic2.core.managers.logmanager import LogManager
|
|
8
|
+
|
|
9
|
+
LOG = LogManager()
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class DicomImage(FileData):
|
|
13
|
+
def load(self):
|
|
14
|
+
if self.path():
|
|
15
|
+
p = load_dicom(self.path())
|
|
16
|
+
if p:
|
|
17
|
+
if is_jpeg2000_compressed(p):
|
|
18
|
+
p.decompress()
|
|
19
|
+
self.set_object(p)
|
|
20
|
+
return True
|
|
21
|
+
# if is_dicom(self.path()):
|
|
22
|
+
# p = load_dicom(self.path())
|
|
23
|
+
# if is_jpeg2000_compressed(p):
|
|
24
|
+
# p.decompress()
|
|
25
|
+
# self.set_object(p)
|
|
26
|
+
# return True
|
|
27
|
+
return False
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from mosamatic2.core.data.filedata import FileData
|
|
3
|
+
from mosamatic2.core.data.dicomimage import DicomImage
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class DicomImageSeries(FileData):
|
|
7
|
+
def __init__(self):
|
|
8
|
+
super(DicomImageSeries, self).__init__()
|
|
9
|
+
self._images = []
|
|
10
|
+
|
|
11
|
+
def images(self):
|
|
12
|
+
return self._images
|
|
13
|
+
|
|
14
|
+
def load(self):
|
|
15
|
+
if self.path():
|
|
16
|
+
images = []
|
|
17
|
+
for f in os.listdir(self.path()):
|
|
18
|
+
f_path = os.path.join(self.path(), f)
|
|
19
|
+
image = DicomImage()
|
|
20
|
+
image.set_path(f_path)
|
|
21
|
+
if image.load():
|
|
22
|
+
images.append(image)
|
|
23
|
+
# Sort DICOM objects by instance number
|
|
24
|
+
self._images = sorted(images, key=lambda image: int(image.object().get('InstanceNumber')))
|
|
25
|
+
return True
|
|
26
|
+
return False
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from mosamatic2.core.data.filedata import FileData
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class DixonSeries(FileData):
|
|
5
|
+
def __init__(self):
|
|
6
|
+
super(DixonSeries, self).__init__()
|
|
7
|
+
self._series = {'ip': None, 'op': None, 'water': None, 'fat': None}
|
|
8
|
+
|
|
9
|
+
def ip(self):
|
|
10
|
+
return self._series['ip']
|
|
11
|
+
|
|
12
|
+
def op(self):
|
|
13
|
+
return self._series['op']
|
|
14
|
+
|
|
15
|
+
def water(self):
|
|
16
|
+
return self._series['water']
|
|
17
|
+
|
|
18
|
+
def fat(self):
|
|
19
|
+
return self._series['fat']
|
|
20
|
+
|
|
21
|
+
def load(self):
|
|
22
|
+
pass
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class FileData:
|
|
5
|
+
def __init__(self):
|
|
6
|
+
self._path = None
|
|
7
|
+
self._name = None
|
|
8
|
+
self._object = None
|
|
9
|
+
|
|
10
|
+
def path(self):
|
|
11
|
+
return self._path
|
|
12
|
+
|
|
13
|
+
def set_path(self, path):
|
|
14
|
+
self._path = path
|
|
15
|
+
|
|
16
|
+
def name(self):
|
|
17
|
+
return os.path.split(self.path())[1]
|
|
18
|
+
|
|
19
|
+
def object(self):
|
|
20
|
+
return self._object
|
|
21
|
+
|
|
22
|
+
def set_object(self, object):
|
|
23
|
+
self._object = object
|
|
24
|
+
|
|
25
|
+
def load(self):
|
|
26
|
+
raise NotImplementedError()
|