mosamatic2 2.0.16__tar.gz → 2.0.18__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of mosamatic2 might be problematic. Click here for more details.

Files changed (115) hide show
  1. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/PKG-INFO +4 -4
  2. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/pyproject.toml +4 -4
  3. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/cli.py +6 -0
  4. mosamatic2-2.0.18/src/mosamatic2/commands/calculatemaskstatistics.py +59 -0
  5. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/commands/defaultdockerpipeline.py +12 -1
  6. mosamatic2-2.0.18/src/mosamatic2/commands/liveranalysispipeline.py +61 -0
  7. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/commands/totalsegmentator.py +11 -2
  8. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/core/pipelines/__init__.py +2 -1
  9. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/core/pipelines/defaultdockerpipeline/defaultdockerpipeline.py +2 -9
  10. mosamatic2-2.0.18/src/mosamatic2/core/pipelines/liveranalysispipeline/liveranalysispipeline.py +48 -0
  11. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/core/tasks/__init__.py +2 -1
  12. mosamatic2-2.0.18/src/mosamatic2/core/tasks/calculatemaskstatisticstask/calculatemaskstatisticstask.py +104 -0
  13. mosamatic2-2.0.18/src/mosamatic2/core/tasks/totalsegmentatortask/totalsegmentatortask.py +75 -0
  14. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/ui/mainwindow.py +30 -0
  15. mosamatic2-2.0.18/src/mosamatic2/ui/resources/VERSION +1 -0
  16. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/ui/widgets/panels/pipelines/defaultdockerpipelinepanel.py +5 -1
  17. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/ui/widgets/panels/pipelines/defaultpipelinepanel.py +1 -1
  18. mosamatic2-2.0.18/src/mosamatic2/ui/widgets/panels/pipelines/liveranalysispipelinepanel.py +187 -0
  19. mosamatic2-2.0.18/src/mosamatic2/ui/widgets/panels/tasks/calculatemaskstatisticstaskpanel.py +215 -0
  20. mosamatic2-2.0.18/src/mosamatic2/ui/widgets/panels/visualizations/__init__.py +0 -0
  21. mosamatic2-2.0.18/src/mosamatic2/ui/widgets/panels/visualizations/slicevisualization/__init__.py +0 -0
  22. mosamatic2-2.0.16/src/mosamatic2/core/tasks/totalsegmentatortask/totalsegmentatortask.py +0 -50
  23. mosamatic2-2.0.16/src/mosamatic2/ui/resources/VERSION +0 -1
  24. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/README.md +0 -0
  25. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/models.py +0 -0
  26. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/__init__.py +0 -0
  27. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/app.py +0 -0
  28. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/commands/__init__.py +0 -0
  29. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/commands/boadockerpipeline.py +0 -0
  30. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/commands/calculatescores.py +0 -0
  31. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/commands/createdicomsummary.py +0 -0
  32. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/commands/createpngsfromsegmentations.py +0 -0
  33. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/commands/defaultpipeline.py +0 -0
  34. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/commands/dicom2nifti.py +0 -0
  35. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/commands/rescaledicomimages.py +0 -0
  36. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/commands/segmentmusclefatl3tensorflow.py +0 -0
  37. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/commands/selectslicefromscans.py +0 -0
  38. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/constants.py +0 -0
  39. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/core/__init__.py +0 -0
  40. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/core/data/__init__.py +0 -0
  41. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/core/data/dicomimage.py +0 -0
  42. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/core/data/dicomimageseries.py +0 -0
  43. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/core/data/dixonseries.py +0 -0
  44. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/core/data/filedata.py +0 -0
  45. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/core/data/multidicomimage.py +0 -0
  46. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/core/data/multiniftiimage.py +0 -0
  47. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/core/data/multinumpyimage.py +0 -0
  48. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/core/data/niftiimage.py +0 -0
  49. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/core/data/numpyimage.py +0 -0
  50. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/core/managers/__init__.py +0 -0
  51. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/core/managers/logmanager.py +0 -0
  52. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/core/managers/logmanagerlistener.py +0 -0
  53. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/core/pipelines/boadockerpipeline/__init__.py +0 -0
  54. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/core/pipelines/boadockerpipeline/boadockerpipeline.py +0 -0
  55. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/core/pipelines/defaultdockerpipeline/__init__.py +0 -0
  56. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/core/pipelines/defaultpipeline/__init__.py +0 -0
  57. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/core/pipelines/defaultpipeline/defaultpipeline.py +0 -0
  58. {mosamatic2-2.0.16/src/mosamatic2/core/tasks/calculatescorestask → mosamatic2-2.0.18/src/mosamatic2/core/pipelines/liveranalysispipeline}/__init__.py +0 -0
  59. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/core/pipelines/pipeline.py +0 -0
  60. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/core/singleton.py +0 -0
  61. {mosamatic2-2.0.16/src/mosamatic2/core/tasks/createdicomsummarytask → mosamatic2-2.0.18/src/mosamatic2/core/tasks/calculatemaskstatisticstask}/__init__.py +0 -0
  62. {mosamatic2-2.0.16/src/mosamatic2/core/tasks/createpngsfromsegmentationstask → mosamatic2-2.0.18/src/mosamatic2/core/tasks/calculatescorestask}/__init__.py +0 -0
  63. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/core/tasks/calculatescorestask/calculatescorestask.py +0 -0
  64. {mosamatic2-2.0.16/src/mosamatic2/core/tasks/dicom2niftitask → mosamatic2-2.0.18/src/mosamatic2/core/tasks/createdicomsummarytask}/__init__.py +0 -0
  65. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/core/tasks/createdicomsummarytask/createdicomsummarytask.py +0 -0
  66. {mosamatic2-2.0.16/src/mosamatic2/core/tasks/rescaledicomimagestask → mosamatic2-2.0.18/src/mosamatic2/core/tasks/createpngsfromsegmentationstask}/__init__.py +0 -0
  67. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/core/tasks/createpngsfromsegmentationstask/createpngsfromsegmentationstask.py +0 -0
  68. {mosamatic2-2.0.16/src/mosamatic2/core/tasks/segmentmusclefatl3tensorflowtask → mosamatic2-2.0.18/src/mosamatic2/core/tasks/dicom2niftitask}/__init__.py +0 -0
  69. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/core/tasks/dicom2niftitask/dicom2niftitask.py +0 -0
  70. {mosamatic2-2.0.16/src/mosamatic2/core/tasks/selectslicefromscanstask → mosamatic2-2.0.18/src/mosamatic2/core/tasks/rescaledicomimagestask}/__init__.py +0 -0
  71. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/core/tasks/rescaledicomimagestask/rescaledicomimagestask.py +0 -0
  72. {mosamatic2-2.0.16/src/mosamatic2/core/tasks/totalsegmentatortask → mosamatic2-2.0.18/src/mosamatic2/core/tasks/segmentmusclefatl3tensorflowtask}/__init__.py +0 -0
  73. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/core/tasks/segmentmusclefatl3tensorflowtask/paramloader.py +0 -0
  74. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/core/tasks/segmentmusclefatl3tensorflowtask/segmentmusclefatl3tensorflowtask.py +0 -0
  75. {mosamatic2-2.0.16/src/mosamatic2/ui → mosamatic2-2.0.18/src/mosamatic2/core/tasks/selectslicefromscanstask}/__init__.py +0 -0
  76. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/core/tasks/selectslicefromscanstask/selectslicefromscanstask.py +0 -0
  77. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/core/tasks/task.py +0 -0
  78. {mosamatic2-2.0.16/src/mosamatic2/ui/widgets → mosamatic2-2.0.18/src/mosamatic2/core/tasks/totalsegmentatortask}/__init__.py +0 -0
  79. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/core/utils.py +0 -0
  80. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/server.py +0 -0
  81. {mosamatic2-2.0.16/src/mosamatic2/ui/widgets/dialogs → mosamatic2-2.0.18/src/mosamatic2/ui}/__init__.py +0 -0
  82. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/ui/resources/icons/mosamatic2.icns +0 -0
  83. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/ui/resources/icons/mosamatic2.ico +0 -0
  84. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/ui/resources/icons/spinner.gif +0 -0
  85. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/ui/resources/images/body-composition.jpg +0 -0
  86. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/ui/settings.py +0 -0
  87. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/ui/utils.py +0 -0
  88. {mosamatic2-2.0.16/src/mosamatic2/ui/widgets/panels → mosamatic2-2.0.18/src/mosamatic2/ui/widgets}/__init__.py +0 -0
  89. {mosamatic2-2.0.16/src/mosamatic2/ui/widgets/panels/pipelines → mosamatic2-2.0.18/src/mosamatic2/ui/widgets/dialogs}/__init__.py +0 -0
  90. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/ui/widgets/dialogs/dialog.py +0 -0
  91. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/ui/widgets/dialogs/helpdialog.py +0 -0
  92. {mosamatic2-2.0.16/src/mosamatic2/ui/widgets/panels/tasks → mosamatic2-2.0.18/src/mosamatic2/ui/widgets/panels}/__init__.py +0 -0
  93. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/ui/widgets/panels/defaultpanel.py +0 -0
  94. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/ui/widgets/panels/logpanel.py +0 -0
  95. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/ui/widgets/panels/mainpanel.py +0 -0
  96. {mosamatic2-2.0.16/src/mosamatic2/ui/widgets/panels/visualizations → mosamatic2-2.0.18/src/mosamatic2/ui/widgets/panels/pipelines}/__init__.py +0 -0
  97. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/ui/widgets/panels/pipelines/boadockerpipelinepanel.py +0 -0
  98. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/ui/widgets/panels/pipelines/pipelinepanel.py +0 -0
  99. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/ui/widgets/panels/stackedpanel.py +0 -0
  100. {mosamatic2-2.0.16/src/mosamatic2/ui/widgets/panels/visualizations/slicevisualization → mosamatic2-2.0.18/src/mosamatic2/ui/widgets/panels/tasks}/__init__.py +0 -0
  101. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/ui/widgets/panels/tasks/calculatescorestaskpanel.py +0 -0
  102. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/ui/widgets/panels/tasks/createdicomsummarytaskpanel.py +0 -0
  103. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/ui/widgets/panels/tasks/createpngsfromsegmentationstaskpanel.py +0 -0
  104. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/ui/widgets/panels/tasks/dicom2niftitaskpanel.py +0 -0
  105. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/ui/widgets/panels/tasks/rescaledicomimagestaskpanel.py +0 -0
  106. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/ui/widgets/panels/tasks/segmentmusclefatl3tensorflowtaskpanel.py +0 -0
  107. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/ui/widgets/panels/tasks/selectslicefromscanstaskpanel.py +0 -0
  108. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/ui/widgets/panels/tasks/taskpanel.py +0 -0
  109. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/ui/widgets/panels/tasks/totalsegmentatortaskpanel.py +0 -0
  110. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/ui/widgets/panels/visualizations/slicevisualization/custominteractorstyle.py +0 -0
  111. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/ui/widgets/panels/visualizations/slicevisualization/sliceviewer.py +0 -0
  112. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/ui/widgets/panels/visualizations/slicevisualization/slicevisualization.py +0 -0
  113. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/ui/widgets/panels/visualizations/visualization.py +0 -0
  114. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/ui/widgets/splashscreen.py +0 -0
  115. {mosamatic2-2.0.16 → mosamatic2-2.0.18}/src/mosamatic2/ui/worker.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: mosamatic2
3
- Version: 2.0.16
3
+ Version: 2.0.18
4
4
  Summary:
5
5
  Author: Ralph Brecheisen
6
6
  Author-email: r.brecheisen@maastrichtuniversity.nl
@@ -9,9 +9,9 @@ Classifier: Programming Language :: Python :: 3
9
9
  Classifier: Programming Language :: Python :: 3.11
10
10
  Requires-Dist: antspyx (>=0.5.4)
11
11
  Requires-Dist: dicom2nifti (>=2.6.2)
12
- Requires-Dist: docker
12
+ Requires-Dist: docker (>=7.1.0)
13
13
  Requires-Dist: flask (>=3.1.2)
14
- Requires-Dist: moosez
14
+ Requires-Dist: moosez (>=3.0.29)
15
15
  Requires-Dist: nibabel (>=5.3.2)
16
16
  Requires-Dist: numpy (>=1.26.4)
17
17
  Requires-Dist: openpyxl (>=3.1.5)
@@ -23,7 +23,7 @@ Requires-Dist: pyqtgraph (>=0.13.7)
23
23
  Requires-Dist: pyside6-essentials (>=6.9)
24
24
  Requires-Dist: python-gdcm (>=3.0.26)
25
25
  Requires-Dist: scipy (>=1.15.3)
26
- Requires-Dist: slicer
26
+ Requires-Dist: slicer (>=0.0.8)
27
27
  Requires-Dist: tensorboard (==2.15.2)
28
28
  Requires-Dist: tensorboard-data-server (==0.7.2)
29
29
  Requires-Dist: tensorflow (==2.15.*) ; platform_system == "Linux"
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "mosamatic2"
3
- version = "2.0.16"
3
+ version = "2.0.18"
4
4
  description = ""
5
5
  authors = [
6
6
  {name = "Ralph Brecheisen", email = "r.brecheisen@maastrichtuniversity.nl"}
@@ -33,9 +33,9 @@ dependencies = [
33
33
  "antspyx>=0.5.4",
34
34
  "vtk>=9.5.1",
35
35
  "pyqtgraph>=0.13.7",
36
- "moosez",
37
- "docker",
38
- "slicer",
36
+ "moosez>=3.0.29",
37
+ "docker>=7.1.0",
38
+ "slicer>=0.0.8",
39
39
  ]
40
40
 
41
41
  [tool.poetry]
@@ -1,6 +1,7 @@
1
1
  import click
2
2
  from mosamatic2.commands import (
3
3
  calculatescores,
4
+ calculatemaskstatistics,
4
5
  rescaledicomimages,
5
6
  segmentmusclefatl3tensorflow,
6
7
  createpngsfromsegmentations,
@@ -10,6 +11,8 @@ from mosamatic2.commands import (
10
11
  defaultpipeline,
11
12
  defaultdockerpipeline,
12
13
  boadockerpipeline,
14
+ liveranalysispipeline,
15
+ totalsegmentator,
13
16
  )
14
17
  from mosamatic2.core.utils import show_doc_command
15
18
 
@@ -32,6 +35,7 @@ def main():
32
35
 
33
36
 
34
37
  main.add_command(calculatescores.calculatescores)
38
+ main.add_command(calculatemaskstatistics.calculatemaskstatistics)
35
39
  main.add_command(rescaledicomimages.rescaledicomimages)
36
40
  main.add_command(segmentmusclefatl3tensorflow.segmentmusclefatl3tensorflow)
37
41
  main.add_command(createpngsfromsegmentations.createpngsfromsegmentations)
@@ -41,4 +45,6 @@ main.add_command(createdicomsummary.createdicomsummary)
41
45
  main.add_command(defaultpipeline.defaultpipeline)
42
46
  main.add_command(defaultdockerpipeline.defaultdockerpipeline)
43
47
  main.add_command(boadockerpipeline.boadockerpipeline)
48
+ main.add_command(liveranalysispipeline.liveranalysispipeline)
49
+ main.add_command(totalsegmentator.totalsegmentator)
44
50
  main.add_command(show_doc_command(main)) # Special command to show long description for command
@@ -0,0 +1,59 @@
1
+ import click
2
+
3
+ from mosamatic2.core.tasks import CalculateMaskStatisticsTask
4
+
5
+
6
+ @click.command(help='Calculates segmentation mask statistics')
7
+ @click.option(
8
+ '--scans',
9
+ required=True,
10
+ type=click.Path(exists=True),
11
+ help='Directory with scans in NIFTI format',
12
+ )
13
+ @click.option(
14
+ '--masks',
15
+ required=True,
16
+ type=click.Path(exists=True),
17
+ help='Directory with segmentation mask files in NIFTI format',
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 calculatemaskstatistics(scans, masks, output, overwrite):
32
+ """
33
+ Calculates segmentation mask statistics. The following metrics are calculated:
34
+
35
+ (1) Mean radiation attenuation (HU)
36
+ (2) Standard deviation radiation attenuation (HU)
37
+ (3) Segmentation mask volume (mL)
38
+
39
+ Parameters
40
+ ----------
41
+ --scans : str
42
+ Directory with scans in NIFTI format
43
+
44
+ --masks : str
45
+ Directory with segmentation mask files in NIFTI format
46
+
47
+ --output : str
48
+ Path to output directory
49
+
50
+ --overwrite : bool
51
+ Overwrite contents output directory [true|false]
52
+ """
53
+ task = CalculateMaskStatisticsTask(
54
+ inputs={'scans': scans, 'masks': masks},
55
+ params=None,
56
+ output=output,
57
+ overwrite=overwrite,
58
+ )
59
+ task.run()
@@ -16,6 +16,11 @@ from mosamatic2.core.pipelines import DefaultDockerPipeline
16
16
  type=click.Path(),
17
17
  help='Input directory with AI model files (no spaces allowed)'
18
18
  )
19
+ @click.option(
20
+ '--version',
21
+ required=True,
22
+ help='Docker image version'
23
+ )
19
24
  @click.option(
20
25
  '--output',
21
26
  required=True,
@@ -28,7 +33,7 @@ from mosamatic2.core.pipelines import DefaultDockerPipeline
28
33
  default=False,
29
34
  help='Overwrite [true|false]'
30
35
  )
31
- def defaultdockerpipeline(images, model_files, output, overwrite):
36
+ def defaultdockerpipeline(images, model_files, version, output, overwrite):
32
37
  """
33
38
  Runs default L3 analysis pipeline through Docker
34
39
 
@@ -51,6 +56,11 @@ def defaultdockerpipeline(images, model_files, output, overwrite):
51
56
 
52
57
  Warning: This directory path cannot contain any spaces!
53
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
+
54
64
  --output : str
55
65
  Path to output directory (no spaces!)
56
66
 
@@ -66,6 +76,7 @@ def defaultdockerpipeline(images, model_files, output, overwrite):
66
76
  'file_type': 'npy',
67
77
  'fig_width': 10,
68
78
  'fig_height': 10,
79
+ 'version': version,
69
80
  },
70
81
  output=output,
71
82
  overwrite=overwrite,
@@ -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()
@@ -21,13 +21,18 @@ from mosamatic2.core.tasks import TotalSegmentatorTask
21
21
  default='total',
22
22
  help='Comma-separated list of Total Segmentator tasks to run (no spaces!)'
23
23
  )
24
+ @click.option(
25
+ '--format',
26
+ default='dicom',
27
+ help='Process scans in DICOM or NIFTI format [dicom|nifti] (default: dicom)'
28
+ )
24
29
  @click.option(
25
30
  '--overwrite',
26
31
  type=click.BOOL,
27
32
  default=False,
28
33
  help='Overwrite [true|false]'
29
34
  )
30
- def totalsegmentator(scans, tasks, output, overwrite):
35
+ def totalsegmentator(scans, tasks, format, output, overwrite):
31
36
  """
32
37
  Run Total Segmentator on CT scans. If you want to run specialized tasks
33
38
  like "liver_segments" or "liver_vessels" you need an educational license.
@@ -56,12 +61,16 @@ def totalsegmentator(scans, tasks, output, overwrite):
56
61
  --tasks : str
57
62
  Comma-separated list of Total Segmentator tasks to run (no spaces!)
58
63
 
64
+ --format : str
65
+ Process scans in DICOM or NIFTI format. Options: [dicom|nifti]
66
+ Default is 'dicom'.
67
+
59
68
  --overwrite : bool
60
69
  Overwrite contents output directory [true|false]
61
70
  """
62
71
  task = TotalSegmentatorTask(
63
72
  inputs={'scans': scans},
64
- params={'tasks': tasks},
73
+ params={'tasks': tasks, 'format': format},
65
74
  output=output,
66
75
  overwrite=overwrite,
67
76
  )
@@ -1,3 +1,4 @@
1
1
  from mosamatic2.core.pipelines.defaultpipeline.defaultpipeline import DefaultPipeline
2
2
  from mosamatic2.core.pipelines.defaultdockerpipeline.defaultdockerpipeline import DefaultDockerPipeline
3
- from mosamatic2.core.pipelines.boadockerpipeline.boadockerpipeline import BoaDockerPipeline
3
+ from mosamatic2.core.pipelines.boadockerpipeline.boadockerpipeline import BoaDockerPipeline
4
+ from mosamatic2.core.pipelines.liveranalysispipeline.liveranalysispipeline import LiverAnalysisPipeline
@@ -11,15 +11,8 @@ class DefaultDockerPipeline(Pipeline):
11
11
  'images',
12
12
  'model_files',
13
13
  ]
14
- PARAMS = [
15
- 'target_size',
16
- 'file_type',
17
- 'fig_width',
18
- 'fig_height',
19
- 'model_type',
20
- 'model_version',
21
- 'version',
22
- ]
14
+ PARAMS = ['version']
15
+
23
16
  def __init__(self, inputs, params, output, overwrite):
24
17
  super(DefaultDockerPipeline, self).__init__(inputs, params, output, overwrite)
25
18
 
@@ -0,0 +1,48 @@
1
+ import os
2
+ from mosamatic2.core.pipelines.pipeline import Pipeline
3
+ from mosamatic2.core.tasks import (
4
+ Dicom2NiftiTask,
5
+ TotalSegmentatorTask,
6
+ CalculateMaskStatisticsTask,
7
+ )
8
+ from mosamatic2.core.managers.logmanager import LogManager
9
+
10
+ LOG = LogManager()
11
+
12
+
13
+ class LiverAnalysisPipeline(Pipeline):
14
+ INPUTS = ['scans']
15
+ PARAMS = ['compressed']
16
+
17
+ def __init__(self, inputs, params, output, overwrite):
18
+ super(LiverAnalysisPipeline, self).__init__(inputs, params, output, overwrite)
19
+ self.add_task(
20
+ Dicom2NiftiTask(
21
+ inputs={'scans': self.input('scans')},
22
+ params={'compressed': self.param('compressed')},
23
+ output=self.output(),
24
+ overwrite=self.overwrite(),
25
+ )
26
+ )
27
+ self.add_task(
28
+ TotalSegmentatorTask(
29
+ inputs={'scans': os.path.join(self.output(), 'dicom2niftitask')},
30
+ params={
31
+ 'tasks': 'liver_segments',
32
+ 'format': 'nifti',
33
+ },
34
+ output=self.output(),
35
+ overwrite=self.overwrite(),
36
+ )
37
+ )
38
+ self.add_task(
39
+ CalculateMaskStatisticsTask(
40
+ inputs={
41
+ 'scans': os.path.join(self.output(), 'dicom2niftitask'),
42
+ 'masks': os.path.join(self.output(), 'totalsegmentatortask'),
43
+ },
44
+ params=None,
45
+ output=self.output(),
46
+ overwrite=self.overwrite(),
47
+ )
48
+ )
@@ -5,4 +5,5 @@ from mosamatic2.core.tasks.createpngsfromsegmentationstask.createpngsfromsegment
5
5
  from mosamatic2.core.tasks.dicom2niftitask.dicom2niftitask import Dicom2NiftiTask
6
6
  from mosamatic2.core.tasks.selectslicefromscanstask.selectslicefromscanstask import SelectSliceFromScansTask
7
7
  from mosamatic2.core.tasks.createdicomsummarytask.createdicomsummarytask import CreateDicomSummaryTask
8
- from mosamatic2.core.tasks.totalsegmentatortask.totalsegmentatortask import TotalSegmentatorTask
8
+ from mosamatic2.core.tasks.totalsegmentatortask.totalsegmentatortask import TotalSegmentatorTask
9
+ from mosamatic2.core.tasks.calculatemaskstatisticstask.calculatemaskstatisticstask import CalculateMaskStatisticsTask
@@ -0,0 +1,104 @@
1
+ import os
2
+ import numpy as np
3
+ import nibabel as nb
4
+ import pandas as pd
5
+ import matplotlib.pyplot as plt
6
+ from mosamatic2.core.tasks.task import Task
7
+ from mosamatic2.core.managers.logmanager import LogManager
8
+
9
+ LOG = LogManager()
10
+
11
+
12
+ class CalculateMaskStatisticsTask(Task):
13
+ INPUTS = ['scans', 'masks']
14
+ PARAMS = []
15
+
16
+ def __init__(self, inputs, params, output, overwrite):
17
+ super(CalculateMaskStatisticsTask, self).__init__(inputs, params, output, overwrite)
18
+
19
+ def load_scans(self):
20
+ scans = []
21
+ for f in os.listdir(self.input('scans')):
22
+ if f.endswith('.nii.gz'):
23
+ scan = os.path.join(self.input('scans'), f)
24
+ if os.path.isfile(scan):
25
+ scans.append(scan)
26
+ return scans
27
+
28
+ def load_mask_files(self):
29
+ mask_files = []
30
+ for f in os.listdir(self.input('masks')):
31
+ if f.endswith('.nii.gz'):
32
+ mask_file = os.path.join(self.input('masks'), f)
33
+ if os.path.isfile(mask_file):
34
+ mask_files.append(mask_file)
35
+ return mask_files
36
+
37
+ def collect_scan_mask_file_pairs(self, scans, mask_files):
38
+ scan_mask_file_pairs = []
39
+ for scan in scans:
40
+ scan_name = os.path.split(scan)[1][:-7]
41
+ for mask_file in mask_files:
42
+ mask_file_name = os.path.split(mask_file)[1][:-7]
43
+ if scan_name in mask_file_name:
44
+ scan_mask_file_pairs.append((scan, mask_file))
45
+ return scan_mask_file_pairs
46
+
47
+ def get_masked_voxels(self, scan_mask_file_pair):
48
+ scan_image_file = scan_mask_file_pair[0]
49
+ scan_image = nb.load(scan_image_file)
50
+ scan_image_data = scan_image.get_fdata()
51
+ mask_file_image_file = scan_mask_file_pair[1]
52
+ mask_file_image_file_name = os.path.split(mask_file_image_file)[1]
53
+ mask_file_image = nb.load(mask_file_image_file)
54
+ mask_file_image_data = mask_file_image.get_fdata()
55
+ mask = mask_file_image_data > 0
56
+ masked_voxels = scan_image_data[mask]
57
+ return masked_voxels, mask_file_image_file_name
58
+
59
+ def calculate_volume_in_mL(self, mask_file):
60
+ nifti_image = nb.load(mask_file)
61
+ nifti_image_data = nifti_image.get_fdata()
62
+ voxel_dims = nifti_image.header.get_zooms()[:3]
63
+ voxel_volume = np.prod(voxel_dims)
64
+ num_voxels = np.sum(nifti_image_data > 0.5)
65
+ mask_volume = num_voxels * voxel_volume / 1000.0
66
+ return mask_volume
67
+
68
+ def create_histogram_png(self, masked_voxels, file_name):
69
+ histogram_png_file = os.path.join(self.output(), f'{file_name}.png')
70
+ plt.figure(figsize=(8,6))
71
+ plt.hist(masked_voxels, bins=100, color='steelblue', edgecolor='black')
72
+ plt.title(f'Histogram of HU values inside {file_name}')
73
+ plt.xlabel('HU')
74
+ plt.ylabel('Frequency')
75
+ plt.savefig(histogram_png_file, dpi=300, bbox_inches='tight')
76
+ plt.close()
77
+
78
+ def save_data_to_file(self, data):
79
+ csv_file_path = os.path.join(self.output(), 'statistics.csv')
80
+ xls_file_path = os.path.join(self.output(), 'statistics.xlsx')
81
+ df = pd.DataFrame(data=data)
82
+ df.to_csv(csv_file_path, index=False, sep=';')
83
+ df.to_excel(xls_file_path, index=False, engine='openpyxl')
84
+
85
+ def run(self):
86
+ scans = self.load_scans()
87
+ mask_files = self.load_mask_files()
88
+ scan_mask_file_pairs = self.collect_scan_mask_file_pairs(scans, mask_files)
89
+ nr_steps = len(scan_mask_file_pairs)
90
+ data = {
91
+ 'file': [],
92
+ 'mean_HU': [],
93
+ 'std_HU': [],
94
+ 'volume_mL': [],
95
+ }
96
+ for step in range(nr_steps):
97
+ masked_voxels, file_name = self.get_masked_voxels(scan_mask_file_pairs[step])
98
+ data['file'].append(file_name)
99
+ data['mean_HU'].append(round(np.mean(masked_voxels)))
100
+ data['std_HU'].append(round(np.std(masked_voxels)))
101
+ data['volume_mL'].append(round(self.calculate_volume_in_mL(scan_mask_file_pairs[step][1])))
102
+ self.create_histogram_png(masked_voxels, file_name)
103
+ self.set_progress(step, nr_steps)
104
+ self.save_data_to_file(data)
@@ -0,0 +1,75 @@
1
+ import os
2
+ import shutil
3
+ import tempfile
4
+ from totalsegmentator.python_api import totalsegmentator
5
+ from mosamatic2.core.tasks.task import Task
6
+ from mosamatic2.core.managers.logmanager import LogManager
7
+
8
+ LOG = LogManager()
9
+ TOTAL_SEGMENTATOR_OUTPUT_DIR = os.path.join(tempfile.gettempdir(), 'total_segmentator_output')
10
+
11
+
12
+ class TotalSegmentatorTask(Task):
13
+ INPUTS = ['scans']
14
+ PARAMS = ['tasks', 'format']
15
+
16
+ def __init__(self, inputs, params, output, overwrite):
17
+ super(TotalSegmentatorTask, self).__init__(inputs, params, output, overwrite)
18
+ LOG.info(f'Using temporary output directory: {TOTAL_SEGMENTATOR_OUTPUT_DIR}')
19
+
20
+ def load_scan_dirs(self):
21
+ scan_dirs = []
22
+ for d in os.listdir(self.input('scans')):
23
+ scan_dir = os.path.join(self.input('scans'), d)
24
+ if os.path.isdir(scan_dir):
25
+ scan_dirs.append(scan_dir)
26
+ return scan_dirs
27
+
28
+ def load_scans(self):
29
+ scans = []
30
+ for f in os.listdir(self.input('scans')):
31
+ if f.endswith('.nii.gz'):
32
+ scan = os.path.join(self.input('scans'), f)
33
+ if os.path.isfile(scan):
34
+ scans.append(scan)
35
+ return scans
36
+
37
+ def extract_masks(self, scan_dir_or_file):
38
+ os.makedirs(TOTAL_SEGMENTATOR_OUTPUT_DIR, exist_ok=True)
39
+ tasks = self.param('tasks').split(",") if self.param('tasks') else []
40
+ for task in tasks:
41
+ LOG.info(f'Running task {task}...')
42
+ totalsegmentator(input=scan_dir_or_file, output=TOTAL_SEGMENTATOR_OUTPUT_DIR, task=task)
43
+
44
+ def delete_total_segmentator_output(self):
45
+ if os.path.exists(TOTAL_SEGMENTATOR_OUTPUT_DIR):
46
+ shutil.rmtree(TOTAL_SEGMENTATOR_OUTPUT_DIR)
47
+
48
+ def run(self):
49
+ if self.param('format') == 'dicom':
50
+ scan_dirs_or_files = self.load_scan_dirs()
51
+ elif self.param('format') == 'nifti':
52
+ scan_dirs_or_files = self.load_scans()
53
+ else:
54
+ LOG.error('Unknown format: {}'.format(self.param('format')))
55
+ return
56
+ nr_steps = len(scan_dirs_or_files)
57
+ for step in range(nr_steps):
58
+ scan_dir_or_file = scan_dirs_or_files[step]
59
+ scan_dir_or_file_name = os.path.split(scan_dir_or_file)[1]
60
+ if self.param('format') == 'nifti':
61
+ scan_dir_or_file_name = scan_dir_or_file_name[:-7]
62
+ try:
63
+ self.extract_masks(scan_dir_or_file)
64
+ except Exception as e:
65
+ LOG.error(f'{scan_dir_or_file}: Could not extract masks [{str(e)}]. Skipping scan...')
66
+ self.set_progress(step, nr_steps)
67
+ LOG.info(f'Copying temporary output to final output directory...')
68
+ for f in os.listdir(TOTAL_SEGMENTATOR_OUTPUT_DIR):
69
+ if f.endswith('.nii') or f.endswith('.nii.gz'):
70
+ f_path = os.path.join(TOTAL_SEGMENTATOR_OUTPUT_DIR, f)
71
+ target_file = os.path.join(self.output(), f'{scan_dir_or_file_name}_{f}')
72
+ shutil.copyfile(f_path, target_file)
73
+ LOG.info(f'Copied {f} to {target_file}')
74
+ LOG.info('Cleaning up Total Segmentator temporary output...')
75
+ self.delete_total_segmentator_output()
@@ -22,9 +22,11 @@ from mosamatic2.ui.widgets.panels.tasks.dicom2niftitaskpanel import Dicom2NiftiT
22
22
  from mosamatic2.ui.widgets.panels.tasks.createdicomsummarytaskpanel import CreateDicomSummaryTaskPanel
23
23
  from mosamatic2.ui.widgets.panels.tasks.selectslicefromscanstaskpanel import SelectSliceFromScansTaskPanel
24
24
  from mosamatic2.ui.widgets.panels.tasks.totalsegmentatortaskpanel import TotalSegmentatorTaskPanel
25
+ from mosamatic2.ui.widgets.panels.tasks.calculatemaskstatisticstaskpanel import CalculateMaskStatisticsTaskPanel
25
26
  from mosamatic2.ui.widgets.panels.pipelines.defaultpipelinepanel import DefaultPipelinePanel
26
27
  from mosamatic2.ui.widgets.panels.pipelines.defaultdockerpipelinepanel import DefaultDockerPipelinePanel
27
28
  from mosamatic2.ui.widgets.panels.pipelines.boadockerpipelinepanel import BoaDockerPipelinePanel
29
+ from mosamatic2.ui.widgets.panels.pipelines.liveranalysispipelinepanel import LiverAnalysisPipelinePanel
28
30
  from mosamatic2.ui.widgets.panels.visualizations.slicevisualization.slicevisualization import SliceVisualization
29
31
 
30
32
  LOG = LogManager()
@@ -45,9 +47,11 @@ class MainWindow(QMainWindow):
45
47
  self._create_dicom_summary_task_panel = None
46
48
  self._select_slice_from_scans_task_panel = None
47
49
  self._total_segmentator_task_panel = None
50
+ self._calculate_mask_statistics_task_panel = None
48
51
  self._default_pipeline_panel = None
49
52
  self._default_docker_pipeline_panel = None
50
53
  self._boa_docker_pipeline_panel = None
54
+ self._liver_analysis_pipeline_panel = None
51
55
  self._slice_visualization = None
52
56
  self.init_window()
53
57
 
@@ -94,6 +98,8 @@ class MainWindow(QMainWindow):
94
98
  select_slice_from_scans_task_action.triggered.connect(self.handle_select_slice_from_scans_task_action)
95
99
  total_segmentator_task_action = QAction('TotalSegmentatorTask', self)
96
100
  total_segmentator_task_action.triggered.connect(self.handle_total_segmentator_task_action)
101
+ calculate_mask_statistics_task_action = QAction('CalculateMaskStatisticsTask', self)
102
+ calculate_mask_statistics_task_action.triggered.connect(self.handle_calculate_mask_statistics_task_action)
97
103
  tasks_menu = self.menuBar().addMenu('Tasks')
98
104
  tasks_menu.addAction(rescale_dicom_images_task_action)
99
105
  tasks_menu.addAction(segment_muscle_fat_l3_tensorflow_task_action)
@@ -103,6 +109,7 @@ class MainWindow(QMainWindow):
103
109
  tasks_menu.addAction(create_dicom_summary_task_action)
104
110
  tasks_menu.addAction(select_slice_from_scans_task_action)
105
111
  tasks_menu.addAction(total_segmentator_task_action)
112
+ tasks_menu.addAction(calculate_mask_statistics_task_action)
106
113
 
107
114
  def init_pipelines_menu(self):
108
115
  default_pipeline_action = QAction('DefaultPipeline', self)
@@ -111,10 +118,13 @@ class MainWindow(QMainWindow):
111
118
  default_docker_pipeline_action.triggered.connect(self.handle_default_docker_pipeline_action)
112
119
  boa_docker_pipeline_action = QAction('BoaDockerPipeline', self)
113
120
  boa_docker_pipeline_action.triggered.connect(self.handle_boa_docker_pipeline_action)
121
+ liver_analysis_pipeline_action = QAction('LiverAnalysisPipeline', self)
122
+ liver_analysis_pipeline_action.triggered.connect(self.handle_liver_analysis_pipeline_action)
114
123
  pipelines_menu = self.menuBar().addMenu('Pipelines')
115
124
  pipelines_menu.addAction(default_pipeline_action)
116
125
  pipelines_menu.addAction(default_docker_pipeline_action)
117
126
  pipelines_menu.addAction(boa_docker_pipeline_action)
127
+ pipelines_menu.addAction(liver_analysis_pipeline_action)
118
128
 
119
129
  def init_visualizations_menu(self):
120
130
  slice_visualization_action = QAction('SliceVisualization', self)
@@ -143,9 +153,11 @@ class MainWindow(QMainWindow):
143
153
  self._main_panel.add_panel(self.create_dicom_summary_task_panel(), 'createdicomsummarytaskpanel')
144
154
  self._main_panel.add_panel(self.select_slice_from_scans_task_panel(), 'selectslicefromscanstaskpanel')
145
155
  self._main_panel.add_panel(self.total_segmentator_task_panel(), 'totalsegmentatortaskpanel')
156
+ self._main_panel.add_panel(self.calculate_mask_statistics_task_panel(), 'calculatemaskstatisticstaskpanel')
146
157
  self._main_panel.add_panel(self.default_pipeline_panel(), 'defaultpipelinepanel')
147
158
  self._main_panel.add_panel(self.default_docker_pipeline_panel(), 'defaultdockerpipelinepanel')
148
159
  self._main_panel.add_panel(self.boa_docker_pipeline_panel(), 'boadockerpipelinepanel')
160
+ self._main_panel.add_panel(self.liver_analysis_pipeline_panel(), 'liveranalysispipelinepanel')
149
161
  self._main_panel.add_panel(self.slice_visualization(), 'slicevisualization')
150
162
  self._main_panel.select_panel('defaultpipelinepanel')
151
163
  return self._main_panel
@@ -198,6 +210,11 @@ class MainWindow(QMainWindow):
198
210
  self._total_segmentator_task_panel = TotalSegmentatorTaskPanel()
199
211
  return self._total_segmentator_task_panel
200
212
 
213
+ def calculate_mask_statistics_task_panel(self):
214
+ if not self._calculate_mask_statistics_task_panel:
215
+ self._calculate_mask_statistics_task_panel = CalculateMaskStatisticsTaskPanel()
216
+ return self._calculate_mask_statistics_task_panel
217
+
201
218
  def default_pipeline_panel(self):
202
219
  if not self._default_pipeline_panel:
203
220
  self._default_pipeline_panel = DefaultPipelinePanel()
@@ -213,6 +230,11 @@ class MainWindow(QMainWindow):
213
230
  self._boa_docker_pipeline_panel = BoaDockerPipelinePanel()
214
231
  return self._boa_docker_pipeline_panel
215
232
 
233
+ def liver_analysis_pipeline_panel(self):
234
+ if not self._liver_analysis_pipeline_panel:
235
+ self._liver_analysis_pipeline_panel = LiverAnalysisPipelinePanel()
236
+ return self._liver_analysis_pipeline_panel
237
+
216
238
  def slice_visualization(self):
217
239
  if not self._slice_visualization:
218
240
  self._slice_visualization = SliceVisualization()
@@ -249,6 +271,9 @@ class MainWindow(QMainWindow):
249
271
  def handle_total_segmentator_task_action(self):
250
272
  self.main_panel().select_panel('totalsegmentatortaskpanel')
251
273
 
274
+ def handle_calculate_mask_statistics_task_action(self):
275
+ self.main_panel().select_panel('calculatemaskstatisticstaskpanel')
276
+
252
277
  def handle_default_pipeline_action(self):
253
278
  self.main_panel().select_panel('defaultpipelinepanel')
254
279
 
@@ -258,6 +283,9 @@ class MainWindow(QMainWindow):
258
283
  def handle_boa_docker_pipeline_action(self):
259
284
  self.main_panel().select_panel('boadockerpipelinepanel')
260
285
 
286
+ def handle_liver_analysis_pipeline_action(self):
287
+ self.main_panel().select_panel('liveranalysispipelinepanel')
288
+
261
289
  def handle_slice_visualization_action(self):
262
290
  self.main_panel().select_panel('slicevisualization')
263
291
 
@@ -275,9 +303,11 @@ class MainWindow(QMainWindow):
275
303
  self.create_dicom_summary_task_panel().save_inputs_and_parameters()
276
304
  self.select_slice_from_scans_task_panel().save_inputs_and_parameters()
277
305
  self.total_segmentator_task_panel().save_inputs_and_parameters()
306
+ self.calculate_mask_statistics_task_panel().save_inputs_and_parameters()
278
307
  self.default_pipeline_panel().save_inputs_and_parameters()
279
308
  self.default_docker_pipeline_panel().save_inputs_and_parameters()
280
309
  self.boa_docker_pipeline_panel().save_inputs_and_parameters()
310
+ self.liver_analysis_pipeline_panel().save_inputs_and_parameters()
281
311
  self.slice_visualization().save_inputs_and_parameters()
282
312
  return super().closeEvent(event)
283
313