mosamatic2 2.0.5__py3-none-any.whl → 2.0.7__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.

Potentially problematic release.


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

Files changed (28) hide show
  1. mosamatic2/core/pipelines/__init__.py +1 -1
  2. mosamatic2/core/pipelines/defaultpipeline/__init__.py +0 -0
  3. mosamatic2/core/tasks/__init__.py +2 -1
  4. mosamatic2/core/tasks/createdicomsummarytask/__init__.py +0 -0
  5. mosamatic2/core/tasks/createdicomsummarytask/createdicomsummarytask.py +60 -0
  6. mosamatic2/ui/mainwindow.py +34 -0
  7. mosamatic2/ui/resources/VERSION +1 -1
  8. mosamatic2/ui/widgets/panels/pipelines/defaultpipelinepanel.py +2 -2
  9. mosamatic2/ui/widgets/panels/pipelines/pipelinepanel.py +6 -0
  10. mosamatic2/ui/widgets/panels/tasks/calculatescorestaskpanel.py +1 -1
  11. mosamatic2/ui/widgets/panels/tasks/createdicomsummarytaskpanel.py +183 -0
  12. mosamatic2/ui/widgets/panels/tasks/createpngsfromsegmentationstaskpanel.py +1 -1
  13. mosamatic2/ui/widgets/panels/tasks/dicom2niftitaskpanel.py +1 -1
  14. mosamatic2/ui/widgets/panels/tasks/rescaledicomimagestaskpanel.py +1 -1
  15. mosamatic2/ui/widgets/panels/tasks/segmentmusclefatl3tensorflowtaskpanel.py +1 -1
  16. mosamatic2/ui/widgets/panels/tasks/selectslicefromscanstaskpanel.py +1 -1
  17. mosamatic2/ui/widgets/panels/visualizations/__init__.py +0 -0
  18. mosamatic2/ui/widgets/panels/visualizations/slicevisualization/__init__.py +0 -0
  19. mosamatic2/ui/widgets/panels/visualizations/slicevisualization/custominteractorstyle.py +62 -0
  20. mosamatic2/ui/widgets/panels/visualizations/slicevisualization/sliceviewer.py +98 -0
  21. mosamatic2/ui/widgets/panels/visualizations/slicevisualization/slicevisualization.py +106 -0
  22. mosamatic2/ui/widgets/panels/visualizations/visualization.py +6 -0
  23. {mosamatic2-2.0.5.dist-info → mosamatic2-2.0.7.dist-info}/METADATA +3 -1
  24. {mosamatic2-2.0.5.dist-info → mosamatic2-2.0.7.dist-info}/RECORD +28 -17
  25. /mosamatic2/core/pipelines/{defaultpipeline.py → defaultpipeline/defaultpipeline.py} +0 -0
  26. /mosamatic2/ui/widgets/panels/{taskpanel.py → tasks/taskpanel.py} +0 -0
  27. {mosamatic2-2.0.5.dist-info → mosamatic2-2.0.7.dist-info}/WHEEL +0 -0
  28. {mosamatic2-2.0.5.dist-info → mosamatic2-2.0.7.dist-info}/entry_points.txt +0 -0
@@ -1 +1 @@
1
- from mosamatic2.core.pipelines.defaultpipeline import DefaultPipeline
1
+ from mosamatic2.core.pipelines.defaultpipeline.defaultpipeline import DefaultPipeline
File without changes
@@ -3,4 +3,5 @@ from mosamatic2.core.tasks.segmentmusclefatl3tensorflowtask.segmentmusclefatl3te
3
3
  from mosamatic2.core.tasks.calculatescorestask.calculatescorestask import CalculateScoresTask
4
4
  from mosamatic2.core.tasks.createpngsfromsegmentationstask.createpngsfromsegmentationstask import CreatePngsFromSegmentationsTask
5
5
  from mosamatic2.core.tasks.dicom2niftitask.dicom2niftitask import Dicom2NiftiTask
6
- from mosamatic2.core.tasks.selectslicefromscanstask.selectslicefromscanstask import SelectSliceFromScansTask
6
+ from mosamatic2.core.tasks.selectslicefromscanstask.selectslicefromscanstask import SelectSliceFromScansTask
7
+ from mosamatic2.core.tasks.createdicomsummarytask.createdicomsummarytask import CreateDicomSummaryTask
@@ -0,0 +1,60 @@
1
+ import os
2
+ import json
3
+ from mosamatic2.core.tasks.task import Task
4
+ from mosamatic2.core.managers.logmanager import LogManager
5
+ from mosamatic2.core.utils import is_dicom, load_dicom
6
+
7
+ LOG = LogManager()
8
+
9
+
10
+ class CreateDicomSummaryTask(Task):
11
+ INPUTS = ['directory']
12
+ PARAMS = []
13
+
14
+ def __init__(self, inputs, params, output, overwrite):
15
+ super(CreateDicomSummaryTask, self).__init__(inputs, params, output, overwrite)
16
+
17
+ def run(self):
18
+ nr_steps = len(os.listdir(self.input('directory'))) * 2
19
+ LOG.info('Collecting data...')
20
+ data = {}
21
+ step = 0
22
+ for patient_dir_name in os.listdir(self.input('directory')):
23
+ data[patient_dir_name] = {}
24
+ patient_dir_path = os.path.join(self.input('directory'), patient_dir_name)
25
+ for root, dirs, files in os.walk(patient_dir_path):
26
+ for f in files:
27
+ f_path = os.path.join(root, f)
28
+ if is_dicom(f_path):
29
+ p = load_dicom(f_path, stop_before_pixels=True)
30
+ series_instance_uid = p.SeriesInstanceUID
31
+ if not series_instance_uid in data[patient_dir_name].keys():
32
+ data[patient_dir_name][series_instance_uid] = []
33
+ data[patient_dir_name][series_instance_uid].append(p)
34
+ self.set_progress(step, nr_steps)
35
+ step += 1
36
+ LOG.info('Building summary...')
37
+ summary = {
38
+ 'nr_series_per_patient': {},
39
+ }
40
+ # Calculate nr. of series per patient
41
+ for patient_dir_name in data.keys():
42
+ summary['nr_series_per_patient'][patient_dir_name] = len(data[patient_dir_name].keys())
43
+ # Summarize series data per patient
44
+ for patient_dir_name in data.keys():
45
+ summary[patient_dir_name] = {}
46
+ for series_instance_uid in data[patient_dir_name].keys():
47
+ summary[patient_dir_name][series_instance_uid] = {
48
+ 'nr_images': len(data[patient_dir_name][series_instance_uid]),
49
+ 'modality': data[patient_dir_name][series_instance_uid][0].Modality,
50
+ 'image_type': str(data[patient_dir_name][series_instance_uid][0].ImageType),
51
+ 'rows': data[patient_dir_name][series_instance_uid][0].Rows,
52
+ 'columns': data[patient_dir_name][series_instance_uid][0].Columns,
53
+ 'pixel_spacing': str(data[patient_dir_name][series_instance_uid][0].PixelSpacing),
54
+ 'slice_thickness': data[patient_dir_name][series_instance_uid][0].SliceThickness,
55
+ }
56
+ self.set_progress(step, nr_steps)
57
+ step += 1
58
+ LOG.info('Exporting summary...')
59
+ with open(os.path.join(self.output(), 'summary.txt'), 'w') as f:
60
+ json.dump(summary, f, indent=4)
@@ -19,8 +19,10 @@ from mosamatic2.ui.widgets.panels.tasks.segmentmusclefatl3tensorflowtaskpanel im
19
19
  from mosamatic2.ui.widgets.panels.tasks.createpngsfromsegmentationstaskpanel import CreatePngsFromSegmentationsTaskPanel
20
20
  from mosamatic2.ui.widgets.panels.tasks.calculatescorestaskpanel import CalculateScoresTaskPanel
21
21
  from mosamatic2.ui.widgets.panels.tasks.dicom2niftitaskpanel import Dicom2NiftiTaskPanel
22
+ from mosamatic2.ui.widgets.panels.tasks.createdicomsummarytaskpanel import CreateDicomSummaryTaskPanel
22
23
  from mosamatic2.ui.widgets.panels.tasks.selectslicefromscanstaskpanel import SelectSliceFromScansTaskPanel
23
24
  from mosamatic2.ui.widgets.panels.pipelines.defaultpipelinepanel import DefaultPipelinePanel
25
+ from mosamatic2.ui.widgets.panels.visualizations.slicevisualization.slicevisualization import SliceVisualization
24
26
 
25
27
  LOG = LogManager()
26
28
 
@@ -37,8 +39,10 @@ class MainWindow(QMainWindow):
37
39
  self._create_pngs_from_segmentations_task_panel = None
38
40
  self._calculate_scores_task_panel = None
39
41
  self._dicom2nifti_task_panel = None
42
+ self._create_dicom_summary_task_panel = None
40
43
  self._select_slice_from_scans_task_panel = None
41
44
  self._default_pipeline_panel = None
45
+ self._slice_visualization = None
42
46
  self.init_window()
43
47
 
44
48
  def init_window(self):
@@ -57,6 +61,7 @@ class MainWindow(QMainWindow):
57
61
  self.init_app_menu()
58
62
  self.init_tasks_menu()
59
63
  self.init_pipelines_menu()
64
+ self.init_visualizations_menu()
60
65
  if is_macos():
61
66
  self.menuBar().setNativeMenuBar(False)
62
67
 
@@ -77,6 +82,8 @@ class MainWindow(QMainWindow):
77
82
  create_pngs_from_segmentations_task_action.triggered.connect(self.handle_create_pngs_from_segmentations_task_action)
78
83
  dicom2nifti_task_action = QAction('Dicom2NiftiTask', self)
79
84
  dicom2nifti_task_action.triggered.connect(self.handle_dicom2nifti_task_action)
85
+ create_dicom_summary_task_action = QAction('CreateDicomSummaryTask', self)
86
+ create_dicom_summary_task_action.triggered.connect(self.handle_create_dicom_summary_task_action)
80
87
  select_slice_from_scans_task_action = QAction('SelectSliceFromScansTask', self)
81
88
  select_slice_from_scans_task_action.triggered.connect(self.handle_select_slice_from_scans_task_action)
82
89
  tasks_menu = self.menuBar().addMenu('Tasks')
@@ -85,6 +92,7 @@ class MainWindow(QMainWindow):
85
92
  tasks_menu.addAction(calculate_scores_task_action)
86
93
  tasks_menu.addAction(create_pngs_from_segmentations_task_action)
87
94
  tasks_menu.addAction(dicom2nifti_task_action)
95
+ tasks_menu.addAction(create_dicom_summary_task_action)
88
96
  tasks_menu.addAction(select_slice_from_scans_task_action)
89
97
 
90
98
  def init_pipelines_menu(self):
@@ -93,6 +101,12 @@ class MainWindow(QMainWindow):
93
101
  pipelines_menu = self.menuBar().addMenu('Pipelines')
94
102
  pipelines_menu.addAction(default_pipeline_action)
95
103
 
104
+ def init_visualizations_menu(self):
105
+ slice_visualization_action = QAction('SliceVisualization', self)
106
+ slice_visualization_action.triggered.connect(self.handle_slice_visualization_action)
107
+ visualizations_menu = self.menuBar().addMenu('Visualizations')
108
+ visualizations_menu.addAction(slice_visualization_action)
109
+
96
110
  def init_status_bar(self):
97
111
  self.set_status('Ready')
98
112
 
@@ -111,8 +125,10 @@ class MainWindow(QMainWindow):
111
125
  self._main_panel.add_panel(self.create_pngs_from_segmentations_task_panel(), 'createpngsfromsegmentationstaskpanel')
112
126
  self._main_panel.add_panel(self.calculate_scores_task_panel(), 'calculatescorestaskpanel')
113
127
  self._main_panel.add_panel(self.dicom2nifti_task_panel(), 'dicom2niftitaskpanel')
128
+ self._main_panel.add_panel(self.create_dicom_summary_task_panel(), 'createdicomsummarytaskpanel')
114
129
  self._main_panel.add_panel(self.select_slice_from_scans_task_panel(), 'selectslicefromscanstaskpanel')
115
130
  self._main_panel.add_panel(self.default_pipeline_panel(), 'defaultpipelinepanel')
131
+ self._main_panel.add_panel(self.slice_visualization(), 'slicevisualization')
116
132
  self._main_panel.select_panel('defaultpipelinepanel')
117
133
  return self._main_panel
118
134
 
@@ -148,6 +164,11 @@ class MainWindow(QMainWindow):
148
164
  if not self._dicom2nifti_task_panel:
149
165
  self._dicom2nifti_task_panel = Dicom2NiftiTaskPanel()
150
166
  return self._dicom2nifti_task_panel
167
+
168
+ def create_dicom_summary_task_panel(self):
169
+ if not self._create_dicom_summary_task_panel:
170
+ self._create_dicom_summary_task_panel = CreateDicomSummaryTaskPanel()
171
+ return self._create_dicom_summary_task_panel
151
172
 
152
173
  def select_slice_from_scans_task_panel(self):
153
174
  if not self._select_slice_from_scans_task_panel:
@@ -158,6 +179,11 @@ class MainWindow(QMainWindow):
158
179
  if not self._default_pipeline_panel:
159
180
  self._default_pipeline_panel = DefaultPipelinePanel()
160
181
  return self._default_pipeline_panel
182
+
183
+ def slice_visualization(self):
184
+ if not self._slice_visualization:
185
+ self._slice_visualization = SliceVisualization()
186
+ return self._slice_visualization
161
187
 
162
188
  # SETTERS
163
189
 
@@ -181,12 +207,18 @@ class MainWindow(QMainWindow):
181
207
  def handle_dicom2nifti_task_action(self):
182
208
  self.main_panel().select_panel('dicom2niftitaskpanel')
183
209
 
210
+ def handle_create_dicom_summary_task_action(self):
211
+ self.main_panel().select_panel('createdicomsummarytaskpanel')
212
+
184
213
  def handle_select_slice_from_scans_task_action(self):
185
214
  self.main_panel().select_panel('selectslicefromscanstaskpanel')
186
215
 
187
216
  def handle_default_pipeline_action(self):
188
217
  self.main_panel().select_panel('defaultpipelinepanel')
189
218
 
219
+ def handle_slice_visualization_action(self):
220
+ self.main_panel().select_panel('slicevisualization')
221
+
190
222
  def showEvent(self, event):
191
223
  return super().showEvent(event)
192
224
 
@@ -198,8 +230,10 @@ class MainWindow(QMainWindow):
198
230
  self.create_pngs_from_segmentations_task_panel().save_inputs_and_parameters()
199
231
  self.calculate_scores_task_panel().save_inputs_and_parameters()
200
232
  self.dicom2nifti_task_panel().save_inputs_and_parameters()
233
+ self.create_dicom_summary_task_panel().save_inputs_and_parameters()
201
234
  self.select_slice_from_scans_task_panel().save_inputs_and_parameters()
202
235
  self.default_pipeline_panel().save_inputs_and_parameters()
236
+ self.slice_visualization().save_inputs_and_parameters()
203
237
  return super().closeEvent(event)
204
238
 
205
239
  def load_geometry_and_state(self):
@@ -1 +1 @@
1
- 2.0.5
1
+ 2.0.7
@@ -18,7 +18,7 @@ from PySide6.QtCore import (
18
18
  )
19
19
 
20
20
  from mosamatic2.core.managers.logmanager import LogManager
21
- from mosamatic2.ui.widgets.panels.defaultpanel import DefaultPanel
21
+ from mosamatic2.ui.widgets.panels.pipelines.pipelinepanel import PipelinePanel
22
22
  from mosamatic2.ui.settings import Settings
23
23
  from mosamatic2.ui.utils import is_macos
24
24
  from mosamatic2.ui.worker import Worker
@@ -32,7 +32,7 @@ MODEL_TYPE_ITEM_NAMES = ['tensorflow', 'pytorch']
32
32
  MODEL_VERSION_ITEM_NAMES = ['1.0', '2.2']
33
33
 
34
34
 
35
- class DefaultPipelinePanel(DefaultPanel):
35
+ class DefaultPipelinePanel(PipelinePanel):
36
36
  def __init__(self):
37
37
  super(DefaultPipelinePanel, self).__init__()
38
38
  self.set_title(PANEL_TITLE)
@@ -0,0 +1,6 @@
1
+ from mosamatic2.ui.widgets.panels.defaultpanel import DefaultPanel
2
+
3
+
4
+ class PipelinePanel(DefaultPanel):
5
+ def __init__(self):
6
+ super(PipelinePanel, self).__init__()
@@ -17,7 +17,7 @@ from PySide6.QtCore import (
17
17
  )
18
18
 
19
19
  from mosamatic2.core.managers.logmanager import LogManager
20
- from mosamatic2.ui.widgets.panels.taskpanel import TaskPanel
20
+ from mosamatic2.ui.widgets.panels.tasks.taskpanel import TaskPanel
21
21
  from mosamatic2.ui.settings import Settings
22
22
  from mosamatic2.ui.utils import is_macos
23
23
  from mosamatic2.ui.worker import Worker
@@ -0,0 +1,183 @@
1
+ import os
2
+
3
+ from PySide6.QtWidgets import (
4
+ QLineEdit,
5
+ QCheckBox,
6
+ QSpinBox,
7
+ QHBoxLayout,
8
+ QVBoxLayout,
9
+ QFormLayout,
10
+ QPushButton,
11
+ QFileDialog,
12
+ QMessageBox,
13
+ )
14
+ from PySide6.QtCore import (
15
+ QThread,
16
+ Slot,
17
+ )
18
+
19
+ from mosamatic2.core.managers.logmanager import LogManager
20
+ from mosamatic2.ui.widgets.panels.tasks.taskpanel import TaskPanel
21
+ from mosamatic2.ui.settings import Settings
22
+ from mosamatic2.ui.utils import is_macos
23
+ from mosamatic2.ui.worker import Worker
24
+ from mosamatic2.core.tasks import CreateDicomSummaryTask
25
+
26
+ LOG = LogManager()
27
+
28
+ PANEL_TITLE = 'CreateDicomSummaryTaskPanel'
29
+ PANEL_NAME = 'createdicomsummarytaskpanel'
30
+
31
+
32
+ class CreateDicomSummaryTaskPanel(TaskPanel):
33
+ def __init__(self):
34
+ super(CreateDicomSummaryTaskPanel, self).__init__()
35
+ self.set_title(PANEL_TITLE)
36
+ self._images_dir_line_edit = None
37
+ self._images_dir_select_button = None
38
+ self._output_dir_line_edit = None
39
+ self._output_dir_select_button = None
40
+ self._overwrite_checkbox = None
41
+ self._form_layout = None
42
+ self._run_task_button = None
43
+ self._settings = None
44
+ self._task = None
45
+ self._worker = None
46
+ self._thread = None
47
+ self.init_layout()
48
+
49
+ def images_dir_line_edit(self):
50
+ if not self._images_dir_line_edit:
51
+ self._images_dir_line_edit = QLineEdit(self.settings().get(f'{PANEL_NAME}/images_dir'))
52
+ return self._images_dir_line_edit
53
+
54
+ def images_dir_select_button(self):
55
+ if not self._images_dir_select_button:
56
+ self._images_dir_select_button = QPushButton('Select')
57
+ self._images_dir_select_button.clicked.connect(self.handle_images_dir_select_button)
58
+ return self._images_dir_select_button
59
+
60
+ def output_dir_line_edit(self):
61
+ if not self._output_dir_line_edit:
62
+ self._output_dir_line_edit = QLineEdit(self.settings().get(f'{PANEL_NAME}/output_dir'))
63
+ return self._output_dir_line_edit
64
+
65
+ def output_dir_select_button(self):
66
+ if not self._output_dir_select_button:
67
+ self._output_dir_select_button = QPushButton('Select')
68
+ self._output_dir_select_button.clicked.connect(self.handle_output_dir_select_button)
69
+ return self._output_dir_select_button
70
+
71
+ def overwrite_checkbox(self):
72
+ if not self._overwrite_checkbox:
73
+ self._overwrite_checkbox = QCheckBox('')
74
+ self._overwrite_checkbox.setChecked(self.settings().get_bool(f'{PANEL_NAME}/overwrite', True))
75
+ return self._overwrite_checkbox
76
+
77
+ def form_layout(self):
78
+ if not self._form_layout:
79
+ self._form_layout = QFormLayout()
80
+ if is_macos():
81
+ self._form_layout.setFieldGrowthPolicy(QFormLayout.ExpandingFieldsGrow)
82
+ return self._form_layout
83
+
84
+ def run_task_button(self):
85
+ if not self._run_task_button:
86
+ self._run_task_button = QPushButton('Run task')
87
+ self._run_task_button.clicked.connect(self.handle_run_task_button)
88
+ return self._run_task_button
89
+
90
+ def settings(self):
91
+ if not self._settings:
92
+ self._settings = Settings()
93
+ return self._settings
94
+
95
+ def init_layout(self):
96
+ images_dir_layout = QHBoxLayout()
97
+ images_dir_layout.addWidget(self.images_dir_line_edit())
98
+ images_dir_layout.addWidget(self.images_dir_select_button())
99
+ output_dir_layout = QHBoxLayout()
100
+ output_dir_layout.addWidget(self.output_dir_line_edit())
101
+ output_dir_layout.addWidget(self.output_dir_select_button())
102
+ self.form_layout().addRow('Images directory', images_dir_layout)
103
+ self.form_layout().addRow('Output directory', output_dir_layout)
104
+ self.form_layout().addRow('Overwrite', self.overwrite_checkbox())
105
+ layout = QVBoxLayout()
106
+ layout.addLayout(self.form_layout())
107
+ layout.addWidget(self.run_task_button())
108
+ self.setLayout(layout)
109
+ self.setObjectName(PANEL_NAME)
110
+
111
+ def handle_images_dir_select_button(self):
112
+ last_directory = self.settings().get('last_directory')
113
+ directory = QFileDialog.getExistingDirectory(dir=last_directory)
114
+ if directory:
115
+ self.images_dir_line_edit().setText(directory)
116
+ self.settings().set('last_directory', directory)
117
+
118
+ def handle_output_dir_select_button(self):
119
+ last_directory = self.settings().get('last_directory')
120
+ directory = QFileDialog.getExistingDirectory(dir=last_directory)
121
+ if directory:
122
+ self.output_dir_line_edit().setText(directory)
123
+ self.settings().set('last_directory', directory)
124
+
125
+ def handle_run_task_button(self):
126
+ errors = self.check_inputs_and_parameters()
127
+ if len(errors) > 0:
128
+ error_message = 'Following errors were encountered:\n'
129
+ for error in errors:
130
+ error_message += f' - {error}\n'
131
+ QMessageBox.information(self, 'Error', error_message)
132
+ else:
133
+ LOG.info('Running task...')
134
+ self.run_task_button().setEnabled(False)
135
+ self.save_inputs_and_parameters()
136
+ self._task = CreateDicomSummaryTask(
137
+ inputs={'directory': self.images_dir_line_edit().text()},
138
+ params=None,
139
+ output=self.output_dir_line_edit().text(),
140
+ overwrite=self.overwrite_checkbox().isChecked(),
141
+ )
142
+ self._worker = Worker(self._task)
143
+ self._thread = QThread()
144
+ self._worker.moveToThread(self._thread)
145
+ self._thread.started.connect(self._worker.run)
146
+ self._worker.progress.connect(self.handle_progress)
147
+ self._worker.status.connect(self.handle_status)
148
+ self._worker.finished.connect(self.handle_finished)
149
+ self._worker.finished.connect(self._thread.quit)
150
+ self._worker.finished.connect(self._worker.deleteLater)
151
+ self._thread.finished.connect(self._thread.deleteLater)
152
+ self._thread.start()
153
+
154
+ @Slot(int)
155
+ def handle_progress(self, progress):
156
+ LOG.info(f'Progress: {progress} / 100%')
157
+
158
+ @Slot(str)
159
+ def handle_status(self, status):
160
+ LOG.info(f'Status: {status}')
161
+
162
+ @Slot()
163
+ def handle_finished(self):
164
+ self.run_task_button().setEnabled(True)
165
+
166
+ # HELPERS
167
+
168
+ def check_inputs_and_parameters(self):
169
+ errors = []
170
+ if self.images_dir_line_edit().text() == '':
171
+ errors.append('Empty images directory path')
172
+ if not os.path.isdir(self.images_dir_line_edit().text()):
173
+ errors.append('Images directory does not exist')
174
+ if self.output_dir_line_edit().text() == '':
175
+ errors.append('Empty output directory path')
176
+ if os.path.isdir(self.output_dir_line_edit().text()) and not self.overwrite_checkbox().isChecked():
177
+ errors.append('Output directory exists but overwrite=False. Please remove output directory first')
178
+ return errors
179
+
180
+ def save_inputs_and_parameters(self):
181
+ self.settings().set(f'{PANEL_NAME}/images_dir', self.images_dir_line_edit().text())
182
+ self.settings().set(f'{PANEL_NAME}/output_dir', self.output_dir_line_edit().text())
183
+ self.settings().set(f'{PANEL_NAME}/overwrite', self.overwrite_checkbox().isChecked())
@@ -17,7 +17,7 @@ from PySide6.QtCore import (
17
17
  )
18
18
 
19
19
  from mosamatic2.core.managers.logmanager import LogManager
20
- from mosamatic2.ui.widgets.panels.taskpanel import TaskPanel
20
+ from mosamatic2.ui.widgets.panels.tasks.taskpanel import TaskPanel
21
21
  from mosamatic2.ui.settings import Settings
22
22
  from mosamatic2.ui.utils import is_macos
23
23
  from mosamatic2.ui.worker import Worker
@@ -17,7 +17,7 @@ from PySide6.QtCore import (
17
17
  )
18
18
 
19
19
  from mosamatic2.core.managers.logmanager import LogManager
20
- from mosamatic2.ui.widgets.panels.taskpanel import TaskPanel
20
+ from mosamatic2.ui.widgets.panels.tasks.taskpanel import TaskPanel
21
21
  from mosamatic2.ui.settings import Settings
22
22
  from mosamatic2.ui.utils import is_macos
23
23
  from mosamatic2.ui.worker import Worker
@@ -17,7 +17,7 @@ from PySide6.QtCore import (
17
17
  )
18
18
 
19
19
  from mosamatic2.core.managers.logmanager import LogManager
20
- from mosamatic2.ui.widgets.panels.taskpanel import TaskPanel
20
+ from mosamatic2.ui.widgets.panels.tasks.taskpanel import TaskPanel
21
21
  from mosamatic2.ui.settings import Settings
22
22
  from mosamatic2.ui.utils import is_macos
23
23
  from mosamatic2.ui.worker import Worker
@@ -16,7 +16,7 @@ from PySide6.QtCore import (
16
16
  )
17
17
 
18
18
  from mosamatic2.core.managers.logmanager import LogManager
19
- from mosamatic2.ui.widgets.panels.taskpanel import TaskPanel
19
+ from mosamatic2.ui.widgets.panels.tasks.taskpanel import TaskPanel
20
20
  from mosamatic2.ui.settings import Settings
21
21
  from mosamatic2.ui.utils import is_macos
22
22
  from mosamatic2.ui.worker import Worker
@@ -17,7 +17,7 @@ from PySide6.QtCore import (
17
17
  )
18
18
 
19
19
  from mosamatic2.core.managers.logmanager import LogManager
20
- from mosamatic2.ui.widgets.panels.taskpanel import TaskPanel
20
+ from mosamatic2.ui.widgets.panels.tasks.taskpanel import TaskPanel
21
21
  from mosamatic2.ui.settings import Settings
22
22
  from mosamatic2.ui.utils import is_macos
23
23
  from mosamatic2.ui.worker import Worker
@@ -0,0 +1,62 @@
1
+ import vtk
2
+
3
+
4
+ class CustomInteractorStyle(vtk.vtkInteractorStyleImage):
5
+ def __init__(self, image_data, slice_mapper, status_actor, slice_obj, orientation="axial"):
6
+ super(CustomInteractorStyle, self).__init__()
7
+ self.AddObserver("MouseWheelForwardEvent", self.move_slice_forward)
8
+ self.AddObserver("MouseWheelBackwardEvent", self.move_slice_backward)
9
+ self.AddObserver("MouseMoveEvent", self.update_overlay, 1.0)
10
+ self.AddObserver("KeyPressEvent", self.key_press_event)
11
+
12
+ self.image_data = image_data
13
+ self.slice_mapper = slice_mapper
14
+ self.status_actor = status_actor
15
+ self.slice_obj = slice_obj
16
+ self.orientation = orientation
17
+
18
+ xmin, xmax, ymin, ymax, zmin, zmax = image_data.GetExtent()
19
+ if orientation == "axial":
20
+ self.min_slice, self.max_slice = zmin, zmax
21
+ elif orientation == "sagittal":
22
+ self.min_slice, self.max_slice = xmin, xmax
23
+ elif orientation == "coronal":
24
+ self.min_slice, self.max_slice = ymin, ymax
25
+ else:
26
+ raise ValueError(f"Unknown orientation: {orientation}")
27
+
28
+ self.slice = (self.min_slice + self.max_slice) // 2
29
+ self.slice_mapper.SetSliceNumber(self.slice)
30
+ self.update_status_message()
31
+
32
+ def update_status_message(self):
33
+ window = int(self.slice_obj.GetProperty().GetColorWindow())
34
+ level = int(self.slice_obj.GetProperty().GetColorLevel())
35
+ message = f'Slice {self.slice + 1}/{self.max_slice + 1} | W: {window} L: {level}'
36
+ self.status_actor.GetMapper().SetInput(message)
37
+
38
+ def move_slice_forward(self, obj, event):
39
+ if self.slice < self.max_slice:
40
+ self.slice += 1
41
+ self.slice_mapper.SetSliceNumber(self.slice)
42
+ self.update_status_message()
43
+ self.GetInteractor().GetRenderWindow().Render()
44
+
45
+ def move_slice_backward(self, obj, event):
46
+ if self.slice > self.min_slice:
47
+ self.slice -= 1
48
+ self.slice_mapper.SetSliceNumber(self.slice)
49
+ self.update_status_message()
50
+ self.GetInteractor().GetRenderWindow().Render()
51
+
52
+ def key_press_event(self, obj, event):
53
+ key = self.GetInteractor().GetKeySym()
54
+ if key == "Up":
55
+ self.move_slice_forward(obj, event)
56
+ elif key == "Down":
57
+ self.move_slice_backward(obj, event)
58
+
59
+ def update_overlay(self, obj, event):
60
+ super(CustomInteractorStyle, self).OnMouseMove()
61
+ self.update_status_message()
62
+ self.GetInteractor().GetRenderWindow().Render()
@@ -0,0 +1,98 @@
1
+ import os
2
+ import vtk
3
+ import pydicom
4
+ from PySide6.QtWidgets import QWidget, QVBoxLayout, QMessageBox
5
+ from mosamatic2.ui.widgets.panels.visualizations.slicevisualization.custominteractorstyle import CustomInteractorStyle
6
+ from vtkmodules.qt.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor
7
+
8
+ COLOR_WINDOW = 400
9
+ COLOR_LEVEL = 40
10
+ IMAGE_SHIFT_SCALE = -1000
11
+
12
+
13
+ class SliceViewer(QWidget):
14
+ def __init__(self):
15
+ super(SliceViewer, self).__init__()
16
+ self._nifti_file_or_dicom_dir = None
17
+ self._view_orientation = 'axial'
18
+ self._vtk_widget = QVTKRenderWindowInteractor(self)
19
+ self._render_window = self._vtk_widget.GetRenderWindow()
20
+ self._interactor = self._render_window.GetInteractor()
21
+ self._interactor_style = None
22
+ layout = QVBoxLayout()
23
+ layout.addWidget(self._vtk_widget)
24
+ self.setLayout(layout)
25
+ self._default_renderer = vtk.vtkRenderer()
26
+ self._default_renderer.SetBackground(0.0, 0.0, 0.0) # black
27
+ self._render_window.AddRenderer(self._default_renderer)
28
+ self._render_window.Render()
29
+
30
+ def nifti_file_or_dicom_dir(self):
31
+ return self._nifti_file_or_dicom_dir
32
+
33
+ def set_nifti_file_or_dicom_dir(self, nifti_file_or_dicom_dir):
34
+ self._nifti_file_or_dicom_dir = nifti_file_or_dicom_dir
35
+
36
+ def create_text_actor(self, text, x, y, font_size, align_bottom=False, normalized=False):
37
+ text_prop = vtk.vtkTextProperty()
38
+ text_prop.SetFontFamilyToCourier()
39
+ text_prop.SetFontSize(font_size)
40
+ text_prop.SetVerticalJustificationToBottom() if align_bottom else text_prop.SetVerticalJustificationToTop()
41
+ text_prop.SetJustificationToLeft()
42
+ text_mapper = vtk.vtkTextMapper()
43
+ text_mapper.SetInput(text)
44
+ text_mapper.SetTextProperty(text_prop)
45
+ text_actor = vtk.vtkActor2D()
46
+ text_actor.SetMapper(text_mapper)
47
+ if normalized:
48
+ text_actor.GetPositionCoordinate().SetCoordinateSystemToNormalizedDisplay()
49
+ text_actor.SetPosition(x, y)
50
+ return text_actor
51
+
52
+ def is_nifti_file(self, file_path):
53
+ return file_path.endswith('.nii') or file_path.endswith('.nii.gz')
54
+
55
+ def is_dicom_dir(self, dir_path):
56
+ first_dicom_file = os.path.join(dir_path, os.listdir(dir_path)[0])
57
+ return pydicom.dcmread(first_dicom_file, stop_before_pixels=True)
58
+
59
+ def load_image(self):
60
+ if not self.nifti_file_or_dicom_dir():
61
+ QMessageBox.warning(self, 'Warning', 'No NIFTI file or DICOM directory set')
62
+ return
63
+ if self.is_nifti_file(self.nifti_file_or_dicom_dir()):
64
+ reader = vtk.vtkNIFTIImageReader()
65
+ reader.SetFileName(self.nifti_file_or_dicom_dir())
66
+ elif self.is_dicom_dir(self.nifti_file_or_dicom_dir()):
67
+ reader = vtk.vtkDICOMImageReader()
68
+ reader.SetDirectoryName(self.nifti_file_or_dicom_dir())
69
+ reader.Update()
70
+ image_data = reader.GetOutput()
71
+ xmin, xmax, ymin, ymax, zmin, zmax = image_data.GetExtent()
72
+ axial_index = (zmin + zmax) // 2
73
+ slice_mapper = vtk.vtkImageSliceMapper()
74
+ slice_mapper.SetInputData(image_data)
75
+ slice_mapper.SetOrientationToZ() # axial orientation
76
+ slice_mapper.SetSliceNumber(axial_index)
77
+ slice = vtk.vtkImageSlice()
78
+ slice.GetProperty().SetColorWindow(400)
79
+ slice.GetProperty().SetColorLevel(40)
80
+ slice.SetMapper(slice_mapper)
81
+ slice_text_actor = self.create_text_actor("", 0.01, 0.01, 12, align_bottom=True, normalized=True)
82
+ usage_text_actor = self.create_text_actor(
83
+ "- Slice with mouse wheel or Up/Down-Key (first click inside viewer)\n"
84
+ "- Zoom with pressed right mouse button while dragging\n"
85
+ "- Pan with middle mouse button while dragging\n"
86
+ "- Change contrast/brightness with pressed left mouse while dragging",
87
+ 0.01, 0.99, 12, normalized=True)
88
+ ren = vtk.vtkRenderer()
89
+ ren.AddActor2D(slice_text_actor)
90
+ ren.AddActor2D(usage_text_actor)
91
+ ren.AddViewProp(slice)
92
+ ren.ResetCamera()
93
+ self._render_window.RemoveRenderer(self._default_renderer)
94
+ self._render_window.AddRenderer(ren)
95
+ self._interactor_style = CustomInteractorStyle(image_data, slice_mapper, slice_text_actor, slice)
96
+ self._interactor.SetInteractorStyle(self._interactor_style)
97
+ self._interactor.Initialize()
98
+ self._render_window.Render()
@@ -0,0 +1,106 @@
1
+ from PySide6.QtWidgets import (
2
+ QLineEdit,
3
+ QHBoxLayout,
4
+ QVBoxLayout,
5
+ QFormLayout,
6
+ QPushButton,
7
+ QFileDialog,
8
+ )
9
+ from mosamatic2.ui.widgets.panels.visualizations.visualization import Visualization
10
+ from mosamatic2.ui.widgets.panels.visualizations.slicevisualization.sliceviewer import SliceViewer
11
+ from mosamatic2.core.managers.logmanager import LogManager
12
+ from mosamatic2.ui.settings import Settings
13
+ from mosamatic2.ui.utils import is_macos
14
+
15
+ LOG = LogManager()
16
+ PANEL_TITLE = 'SliceVisualization'
17
+ PANEL_NAME = 'slicevisualization'
18
+
19
+
20
+ class SliceVisualization(Visualization):
21
+ def __init__(self):
22
+ super(SliceVisualization, self).__init__()
23
+ self.set_title(PANEL_TITLE)
24
+ self._image_line_edit = None
25
+ self._image_select_button = None
26
+ self._image_dir_select_button = None
27
+ self._load_image_button = None
28
+ self._slice_viewer = None
29
+ self._form_layout = None
30
+ self._settings = None
31
+ self.init_layout()
32
+
33
+ def image_line_edit(self):
34
+ if not self._image_line_edit:
35
+ self._image_line_edit = QLineEdit(self.settings().get(f'{PANEL_NAME}/image'))
36
+ return self._image_line_edit
37
+
38
+ def image_select_button(self):
39
+ if not self._image_select_button:
40
+ self._image_select_button = QPushButton('Select Image')
41
+ self._image_select_button.clicked.connect(self.handle_image_select_button)
42
+ return self._image_select_button
43
+
44
+ def image_dir_select_button(self):
45
+ if not self._image_dir_select_button:
46
+ self._image_dir_select_button = QPushButton('Select Directory')
47
+ self._image_dir_select_button.clicked.connect(self.handle_image_dir_select_button)
48
+ return self._image_dir_select_button
49
+
50
+ def load_image_button(self):
51
+ if not self._load_image_button:
52
+ self._load_image_button = QPushButton('Load')
53
+ self._load_image_button.clicked.connect(self.handle_load_image_button)
54
+ return self._load_image_button
55
+
56
+ def slice_viewer(self):
57
+ if not self._slice_viewer:
58
+ self._slice_viewer = SliceViewer()
59
+ return self._slice_viewer
60
+
61
+ def form_layout(self):
62
+ if not self._form_layout:
63
+ self._form_layout = QFormLayout()
64
+ if is_macos():
65
+ self._form_layout.setFieldGrowthPolicy(QFormLayout.ExpandingFieldsGrow)
66
+ return self._form_layout
67
+
68
+ def settings(self):
69
+ if not self._settings:
70
+ self._settings = Settings()
71
+ return self._settings
72
+
73
+ def init_layout(self):
74
+ image_layout = QHBoxLayout()
75
+ image_layout.addWidget(self.image_line_edit())
76
+ image_layout.addWidget(self.image_select_button())
77
+ image_layout.addWidget(self.image_dir_select_button())
78
+ self.form_layout().addRow('NIFTI file or DICOM directory', image_layout)
79
+ layout = QVBoxLayout()
80
+ layout.addLayout(self.form_layout())
81
+ layout.addWidget(self.load_image_button())
82
+ layout.addWidget(self.slice_viewer())
83
+ self.setLayout(layout)
84
+ self.setObjectName(PANEL_NAME)
85
+
86
+ def handle_image_select_button(self):
87
+ last_directory = self.settings().get('last_directory')
88
+ file_path, _ = QFileDialog.getOpenFileName(dir=last_directory)
89
+ if file_path:
90
+ self.image_line_edit().setText(file_path)
91
+ self.settings().set('last_directory', file_path)
92
+
93
+ def handle_image_dir_select_button(self):
94
+ last_directory = self.settings().get('last_directory')
95
+ dir_path = QFileDialog.getExistingDirectory(dir=last_directory)
96
+ if dir_path:
97
+ self.image_line_edit().setText(dir_path)
98
+ self.settings().set('last_directory', dir_path)
99
+
100
+ def handle_load_image_button(self):
101
+ self.slice_viewer().set_nifti_file_or_dicom_dir(self.image_line_edit().text())
102
+ # self.slice_viewer().set_view_orientation('axial')
103
+ self.slice_viewer().load_image()
104
+
105
+ def save_inputs_and_parameters(self):
106
+ self.settings().set(f'{PANEL_NAME}/image', self.image_line_edit().text())
@@ -0,0 +1,6 @@
1
+ from mosamatic2.ui.widgets.panels.defaultpanel import DefaultPanel
2
+
3
+
4
+ class Visualization(DefaultPanel):
5
+ def __init__(self):
6
+ super(Visualization, self).__init__()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: mosamatic2
3
- Version: 2.0.5
3
+ Version: 2.0.7
4
4
  Summary:
5
5
  Author: Ralph Brecheisen
6
6
  Author-email: r.brecheisen@maastrichtuniversity.nl
@@ -17,6 +17,7 @@ Requires-Dist: pandas (>=2.3.2)
17
17
  Requires-Dist: pendulum (>=3.1.0)
18
18
  Requires-Dist: pillow (>=11.3.0)
19
19
  Requires-Dist: pydicom (>=3.0.1)
20
+ Requires-Dist: pyqtgraph (>=0.13.7)
20
21
  Requires-Dist: pyside6-essentials (>=6.9)
21
22
  Requires-Dist: python-gdcm (>=3.0.26)
22
23
  Requires-Dist: scipy (>=1.15.3)
@@ -30,6 +31,7 @@ Requires-Dist: tensorflow-macos (==2.15.0) ; platform_system == "Darwin" and pla
30
31
  Requires-Dist: torch (>=2.8.0)
31
32
  Requires-Dist: torchvision (>=0.23.0)
32
33
  Requires-Dist: totalsegmentator (>=2.11.0)
34
+ Requires-Dist: vtk (>=9.5.1)
33
35
  Description-Content-Type: text/markdown
34
36
 
35
37
 
@@ -22,13 +22,16 @@ mosamatic2/core/data/numpyimage.py,sha256=ZbJ9JRAVOgvXzTZ6kscEuGZJqKT-MPdt42IAlm
22
22
  mosamatic2/core/managers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
23
  mosamatic2/core/managers/logmanager.py,sha256=NEaXvhl0aILjBbK710GaWanVuuNvB51HpHhE5rgYvng,1391
24
24
  mosamatic2/core/managers/logmanagerlistener.py,sha256=Gaig07yjBnyQq9I8sN85olTEeDCDyCFQnEJdwzvmgvc,99
25
- mosamatic2/core/pipelines/__init__.py,sha256=MXoylu34AlcyudJpjuLa4B7K9gZmxLnZGDaEkK9Ygio,69
26
- mosamatic2/core/pipelines/defaultpipeline.py,sha256=EUblRhLZXhslz9bdBmx8v9yjpgOdsHviqQZ5elK8gNQ,2901
25
+ mosamatic2/core/pipelines/__init__.py,sha256=Esb4TQFvY2soU2dfQPgVlhfTx1LdxYrPBiuAKDosHqA,85
26
+ mosamatic2/core/pipelines/defaultpipeline/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
+ mosamatic2/core/pipelines/defaultpipeline/defaultpipeline.py,sha256=EUblRhLZXhslz9bdBmx8v9yjpgOdsHviqQZ5elK8gNQ,2901
27
28
  mosamatic2/core/pipelines/pipeline.py,sha256=mRxKXLKwgKDpc8R9mCI6gDKGJ2lKVxRQ__Sf0Mfn_Qc,384
28
29
  mosamatic2/core/singleton.py,sha256=FV0k_LlOCmFhlWN6gf1c2x7YXWyd8-7DsIMvOKrI6NY,224
29
- mosamatic2/core/tasks/__init__.py,sha256=az_IatVtpT7M2AiOl7ez6EW_oR7_n9GtC1nL0_mYwZk,655
30
+ mosamatic2/core/tasks/__init__.py,sha256=w03AyCk2BQ6gGPBEKhtad6lt9WuwHC-nMztv7wQNwb4,759
30
31
  mosamatic2/core/tasks/calculatescorestask/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
31
32
  mosamatic2/core/tasks/calculatescorestask/calculatescorestask.py,sha256=jEbogrEnEtMbmfQ8KOGSUdGMhdeX69Bv01-82faRIlY,6617
33
+ mosamatic2/core/tasks/createdicomsummarytask/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
34
+ mosamatic2/core/tasks/createdicomsummarytask/createdicomsummarytask.py,sha256=TebP3bI_TAUa93mp5XtnPW5NSVFMvbvb-CQAQnh6RfY,2932
32
35
  mosamatic2/core/tasks/createpngsfromsegmentationstask/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
36
  mosamatic2/core/tasks/createpngsfromsegmentationstask/createpngsfromsegmentationstask.py,sha256=1UpOsp1CH668BQ0g4tALou_tFgisC306VcvqOKSDuTo,1884
34
37
  mosamatic2/core/tasks/dicom2niftitask/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -44,12 +47,12 @@ mosamatic2/core/tasks/task.py,sha256=APPnid6dpSGkPuDqU1vm2RIMR5vkpvbP1CPHUMjympg
44
47
  mosamatic2/core/utils.py,sha256=zh44FNOWxNKuZ4FcM7VIfMvdlzOr4AA8_PJ1r-6_83k,10855
45
48
  mosamatic2/server.py,sha256=jiUc7-aFaDMSY2hg6BhMC9C2FU4V2OrMBSoiIAP8Zcs,4158
46
49
  mosamatic2/ui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
47
- mosamatic2/ui/mainwindow.py,sha256=k5yxHTjwvpwXXWx94sJ45q1BcH-06B9I7Qnqfd1Zbr8,11119
50
+ mosamatic2/ui/mainwindow.py,sha256=nV9RqqSZVoVbU2opJIk7E3n4GvZWtuDETxmzwzmx4mg,13099
48
51
  mosamatic2/ui/resources/icons/mosamatic2.icns,sha256=OfhC-diJTIgaNMOezxKKilGsY7mRkaGdU5dGr0MOjIA,2994125
49
52
  mosamatic2/ui/resources/icons/mosamatic2.ico,sha256=ySD3RYluHK3pgS0Eas7eKrVk_AskdLQ4qs_IT-wNhq4,12229
50
53
  mosamatic2/ui/resources/icons/spinner.gif,sha256=rvaac6GUZauHSPFSOLWr0RmLfjmtZih2Q8knQ2WP3Po,16240
51
54
  mosamatic2/ui/resources/images/body-composition.jpg,sha256=KD-BudbXwThB4lJOZZN-ad5-TZRaaZ5cKTH0Ar1TOZs,21227
52
- mosamatic2/ui/resources/VERSION,sha256=I2Qe9unc-Hx4iKTROuxBK26Iy4oCUcMjfIY6KzAtKAY,8
55
+ mosamatic2/ui/resources/VERSION,sha256=KwH-299m3oBSV3-QDLRQdLqL7fYkxUJhV8qlxIIJb74,8
53
56
  mosamatic2/ui/settings.py,sha256=YEVHYJIfNsqMO3v1pjzgh7Pih9GGoUX7S9s8S-sBNUk,2121
54
57
  mosamatic2/ui/utils.py,sha256=6bbPIrh4RJ_yhQKNZrgPbL4XeUEogjIjbk_e5c3QS5g,853
55
58
  mosamatic2/ui/widgets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -61,19 +64,27 @@ mosamatic2/ui/widgets/panels/defaultpanel.py,sha256=Ry32Xv6ibxm6NdZ7eBOCcisWNcmn
61
64
  mosamatic2/ui/widgets/panels/logpanel.py,sha256=ogswJ6_ryb6u7JeVnOsh2Ez8KWg6jtCFZwij8s87xO4,1861
62
65
  mosamatic2/ui/widgets/panels/mainpanel.py,sha256=KqI8dA7GpLFd2unqVRTBkNxdnh6AWGpVPwQuaEg8PmI,2431
63
66
  mosamatic2/ui/widgets/panels/pipelines/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
64
- mosamatic2/ui/widgets/panels/pipelines/defaultpipelinepanel.py,sha256=cmjbjllDgwA5zP5EpfRwiYyJI7iXEtPAvh4zSXOhCSw,13714
67
+ mosamatic2/ui/widgets/panels/pipelines/defaultpipelinepanel.py,sha256=qkfI4BnLIXqE_YvSQj4sO_FjnK0eVdIMqAZ8sktgI-8,13727
68
+ mosamatic2/ui/widgets/panels/pipelines/pipelinepanel.py,sha256=SlkKme8Wv2Bvp2Alen98mFjv3F5eZCwJylj294gd5uU,178
65
69
  mosamatic2/ui/widgets/panels/stackedpanel.py,sha256=dK1YWuHUzxRhVb5gP0Lu9rAiW4XagjcHmGF__5Lpufk,657
66
- mosamatic2/ui/widgets/panels/taskpanel.py,sha256=t8lIx1P8sS1Fa-aNm6eEha6297pJQNbBRizkobBexz8,170
67
70
  mosamatic2/ui/widgets/panels/tasks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
68
- mosamatic2/ui/widgets/panels/tasks/calculatescorestaskpanel.py,sha256=kWtRI0SnjSzvE4MGTxs2-W8f3X3uP3LRtXnfyAl8HL0,9381
69
- mosamatic2/ui/widgets/panels/tasks/createpngsfromsegmentationstaskpanel.py,sha256=Be7SJfYHDAvPCC52iVqbrgr3CbwnAck37Ph_BbyhKBE,7873
70
- mosamatic2/ui/widgets/panels/tasks/dicom2niftitaskpanel.py,sha256=mb5LxDuhkwA08LcHGigul7xmef_wTGrmr-DZ72O_joc,7474
71
- mosamatic2/ui/widgets/panels/tasks/rescaledicomimagestaskpanel.py,sha256=_K-XM4zvzq_AMugLqN4p87iEsfX594qYSVnfjNlmAfU,7591
72
- mosamatic2/ui/widgets/panels/tasks/segmentmusclefatl3tensorflowtaskpanel.py,sha256=pLEpUXx_vi6PfOykAwp95m5yLRrIvdF_XaupHBOW31U,9624
73
- mosamatic2/ui/widgets/panels/tasks/selectslicefromscanstaskpanel.py,sha256=ysIoX_IHTPBfEhJQkdM54S3ZL24IAeA8A_ldzgr8BwU,8071
71
+ mosamatic2/ui/widgets/panels/tasks/calculatescorestaskpanel.py,sha256=NmPLQizj4x9jgf9UA7VZSjARNHYJB_jrfB0kvaVncdw,9387
72
+ mosamatic2/ui/widgets/panels/tasks/createdicomsummarytaskpanel.py,sha256=cRCaEmjjZP6RwEhezj2Axxuv8uAGe7ZzHoU67asoZ5s,7530
73
+ mosamatic2/ui/widgets/panels/tasks/createpngsfromsegmentationstaskpanel.py,sha256=JFnmYjPemRtXPXV2fk2cjB45fseN5BZ8gI_T1zVLGV8,7879
74
+ mosamatic2/ui/widgets/panels/tasks/dicom2niftitaskpanel.py,sha256=gIv5xo0z2EEfFzHI4Q6H87maf-nPIeC8yIxLL5iWuCw,7480
75
+ mosamatic2/ui/widgets/panels/tasks/rescaledicomimagestaskpanel.py,sha256=ds7JxynpMeNvqfHKtg1LQR23rb3_Y7xoDLbZ2wl-TMw,7597
76
+ mosamatic2/ui/widgets/panels/tasks/segmentmusclefatl3tensorflowtaskpanel.py,sha256=QCEZs9lqaE-XAJuyyrfZVnFkNRyjMw6Cfa-6qP9WaV8,9630
77
+ mosamatic2/ui/widgets/panels/tasks/selectslicefromscanstaskpanel.py,sha256=iZu_li_7Zr3n8nVp-FI1GFV_HuCf_I4NY9PNr9aX-oY,8077
78
+ mosamatic2/ui/widgets/panels/tasks/taskpanel.py,sha256=t8lIx1P8sS1Fa-aNm6eEha6297pJQNbBRizkobBexz8,170
79
+ mosamatic2/ui/widgets/panels/visualizations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
80
+ mosamatic2/ui/widgets/panels/visualizations/slicevisualization/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
81
+ mosamatic2/ui/widgets/panels/visualizations/slicevisualization/custominteractorstyle.py,sha256=GaXmO5SvXwLAnrVtAGglTXgPx6mD0Q6f8gYrGN5WRO4,2644
82
+ mosamatic2/ui/widgets/panels/visualizations/slicevisualization/sliceviewer.py,sha256=DLvTQ-VboPqjViA9EzGTSm4eGmrgYPH0degpxprEWI4,4600
83
+ mosamatic2/ui/widgets/panels/visualizations/slicevisualization/slicevisualization.py,sha256=2cLTHsGrdMMt_dbnq0EUAFSSW7naR6B1neB7RnUOmjQ,4214
84
+ mosamatic2/ui/widgets/panels/visualizations/visualization.py,sha256=JvqTJi7cCGYK1-wrN2oURdCOBoPS2clVUyYglhkoVJg,178
74
85
  mosamatic2/ui/widgets/splashscreen.py,sha256=MS-OczOWfwwEQNQd-JWe9_Mh57css0cSQgbu973rwQo,4056
75
86
  mosamatic2/ui/worker.py,sha256=v7e3gq7MUudgpB1BJW-P7j5wurzu6-HG5m7I6WHgJp0,699
76
- mosamatic2-2.0.5.dist-info/entry_points.txt,sha256=MCUpKkgbej1clgp8EqlLQGs0BIKwGPcBPiVWLfGz9Gw,126
77
- mosamatic2-2.0.5.dist-info/METADATA,sha256=ODtnfcQqYDrCk6jNK9J1vr7eV3XgUi1yT33ctWPzQ_E,1402
78
- mosamatic2-2.0.5.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
79
- mosamatic2-2.0.5.dist-info/RECORD,,
87
+ mosamatic2-2.0.7.dist-info/entry_points.txt,sha256=MCUpKkgbej1clgp8EqlLQGs0BIKwGPcBPiVWLfGz9Gw,126
88
+ mosamatic2-2.0.7.dist-info/METADATA,sha256=aX9U18Z7h4eR4CR3bRliqeGp8VIwSiBGvw9d42MpowU,1467
89
+ mosamatic2-2.0.7.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
90
+ mosamatic2-2.0.7.dist-info/RECORD,,