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

mosamatic2/cli.py CHANGED
@@ -5,6 +5,7 @@ from mosamatic2.commands import (
5
5
  segmentmusclefatl3tensorflow,
6
6
  createpngsfromsegmentations,
7
7
  dicom2nifti,
8
+ selectslicefromscans,
8
9
  )
9
10
  from mosamatic2.core.utils import show_doc_command
10
11
 
@@ -31,4 +32,5 @@ main.add_command(rescaledicomimages.rescaledicomimages)
31
32
  main.add_command(segmentmusclefatl3tensorflow.segmentmusclefatl3tensorflow)
32
33
  main.add_command(createpngsfromsegmentations.createpngsfromsegmentations)
33
34
  main.add_command(dicom2nifti.dicom2nifti)
35
+ main.add_command(selectslicefromscans.selectslicefromscans)
34
36
  main.add_command(show_doc_command(main)) # Special command to show long description for command
@@ -0,0 +1,65 @@
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
+ help='Vertebral level for selecting slice (default: "L3")'
23
+ )
24
+ @click.option(
25
+ '--overwrite',
26
+ type=click.BOOL,
27
+ default=False,
28
+ help='Overwrite [true|false]'
29
+ )
30
+ def selectslicefromscans(scans, vertebra, output, overwrite):
31
+ """
32
+ Selects specific slice from list of CT scans
33
+
34
+ Parameters
35
+ ----------
36
+ --scans : str
37
+ Directory to scans. Each patient's scan should be in a separate
38
+ subdirectory. For example:
39
+
40
+ /scans
41
+ /scans/patient1
42
+ /scans/patient1/file1.dcm
43
+ /scans/patient1/file2.dcm
44
+ ...
45
+ /scans/patient2
46
+ ...
47
+
48
+ --output : str
49
+ Path to output directory where selected slices will be placed. Each
50
+ slice's file name will be the same as the scan directory name, so in
51
+ the example above that would be "patient1", "patient2", etc.
52
+
53
+ --vertebra : str
54
+ Vertebral level where to take slice [L3|T4]
55
+
56
+ --overwrite : bool
57
+ Overwrite contents output directory [true|false]
58
+ """
59
+ task = SelectSliceFromScansTask(
60
+ inputs={'scans': scans},
61
+ params={'vertebra': vertebra},
62
+ output=output,
63
+ overwrite=overwrite,
64
+ )
65
+ task.run()
@@ -0,0 +1,26 @@
1
+ import os
2
+ from mosamatic2.core.managers.logmanager import LogManager
3
+ from mosamatic2.core.data.filedata import FileData
4
+ from mosamatic2.core.data.numpyimage import NumPyImage
5
+
6
+ LOG = LogManager()
7
+
8
+
9
+ class MultiNumPyImage(FileData):
10
+ def __init__(self):
11
+ super(MultiNumPyImage, self).__init__()
12
+ self._images = []
13
+
14
+ def images(self):
15
+ return self._images
16
+
17
+ def load(self):
18
+ if self.path():
19
+ for f in os.listdir(self.path()):
20
+ f_path = os.path.join(self.path(), f)
21
+ image = NumPyImage()
22
+ image.set_path(f_path)
23
+ if image.load():
24
+ self._images.append(image)
25
+ return True
26
+ return False
@@ -0,0 +1,13 @@
1
+ from mosamatic2.core.data.filedata import FileData
2
+ from mosamatic2.core.utils import (
3
+ is_numpy,
4
+ load_numpy_array,
5
+ )
6
+
7
+ class NumPyImage(FileData):
8
+ def load(self):
9
+ if self.path():
10
+ if is_numpy(self.path()):
11
+ self.set_object(load_numpy_array(self.path()))
12
+ return True
13
+ return False
@@ -2,4 +2,5 @@ from mosamatic2.core.tasks.rescaledicomimagestask.rescaledicomimagestask import
2
2
  from mosamatic2.core.tasks.segmentmusclefatl3tensorflowtask.segmentmusclefatl3tensorflowtask import SegmentMuscleFatL3TensorFlowTask
3
3
  from mosamatic2.core.tasks.calculatescorestask.calculatescorestask import CalculateScoresTask
4
4
  from mosamatic2.core.tasks.createpngsfromsegmentationstask.createpngsfromsegmentationstask import CreatePngsFromSegmentationsTask
5
- from mosamatic2.core.tasks.dicom2niftitask.dicom2niftitask import Dicom2NiftiTask
5
+ from mosamatic2.core.tasks.dicom2niftitask.dicom2niftitask import Dicom2NiftiTask
6
+ from mosamatic2.core.tasks.selectslicefromscanstask.selectslicefromscanstask import SelectSliceFromScansTask
@@ -4,10 +4,8 @@ import pandas as pd
4
4
  from mosamatic2.core.tasks.task import Task
5
5
  from mosamatic2.core.managers.logmanager import LogManager
6
6
  from mosamatic2.core.data.multidicomimage import MultiDicomImage
7
+ from mosamatic2.core.data.numpyimage import NumPyImage
7
8
  from mosamatic2.core.utils import (
8
- is_dicom,
9
- load_dicom,
10
- is_jpeg2000_compressed,
11
9
  get_pixels_from_dicom_object,
12
10
  calculate_area,
13
11
  calculate_mean_radiation_attenuation,
@@ -41,13 +39,11 @@ class CalculateScoresTask(Task):
41
39
  if file_type == '.seg.npy':
42
40
  f_seg_name = f_seg_name.removesuffix(file_type)
43
41
  if f_seg_name == f_img_name:
44
- # img_seg_pairs.append((f_img_path, f_seg_path))
45
42
  img_seg_pairs.append((image, f_seg_path))
46
43
  elif file_type == '.tag':
47
44
  f_seg_name = f_seg_name.removesuffix(file_type).removesuffix('.dcm')
48
45
  f_img_name = f_img_name.removesuffix('.dcm')
49
46
  if f_seg_name == f_img_name:
50
- # img_seg_pairs.append((f_img_path, f_seg_path))
51
47
  img_seg_pairs.append((image, f_seg_path))
52
48
  else:
53
49
  raise RuntimeError('Unknown file type')
@@ -78,7 +74,11 @@ class CalculateScoresTask(Task):
78
74
 
79
75
  def load_segmentation(self, f, file_type='npy'):
80
76
  if file_type == 'npy':
81
- return np.load(f)
77
+ segmentation = NumPyImage()
78
+ segmentation.set_path(f)
79
+ if segmentation.load():
80
+ return segmentation.object()
81
+ LOG.error(f'Could not load segmentation file {f}')
82
82
  if file_type == 'tag':
83
83
  pixels = get_pixels_from_tag_file(f)
84
84
  try:
@@ -28,7 +28,7 @@ class SegmentMuscleFatL3TensorFlowTask(Task):
28
28
  def __init__(self, inputs, params, output, overwrite=True):
29
29
  super(SegmentMuscleFatL3TensorFlowTask, self).__init__(inputs, params, output, overwrite)
30
30
 
31
- def load_images(self):
31
+ def load_images(self):
32
32
  image_data = MultiDicomImage()
33
33
  image_data.set_path(self.input('images'))
34
34
  if image_data.load():
@@ -55,7 +55,6 @@ class SegmentMuscleFatL3TensorFlowTask(Task):
55
55
  import tensorflow as tf
56
56
  tfLoaded = True
57
57
  with tempfile.TemporaryDirectory() as model_dir_unzipped:
58
- # model_dir_unzipped = os.path.join(os.path.split(f_path)[0], 'model_unzipped')
59
58
  os.makedirs(model_dir_unzipped, exist_ok=True)
60
59
  with zipfile.ZipFile(f_path) as zipObj:
61
60
  zipObj.extractall(path=model_dir_unzipped)
@@ -65,7 +64,6 @@ class SegmentMuscleFatL3TensorFlowTask(Task):
65
64
  import tensorflow as tf
66
65
  tfLoaded = True
67
66
  with tempfile.TemporaryDirectory() as contour_model_dir_unzipped:
68
- # contour_model_dir_unzipped = os.path.join(os.path.split(f_path)[0], 'contour_model_unzipped')
69
67
  os.makedirs(contour_model_dir_unzipped, exist_ok=True)
70
68
  with zipfile.ZipFile(f_path) as zipObj:
71
69
  zipObj.extractall(path=contour_model_dir_unzipped)
@@ -0,0 +1,109 @@
1
+ import os
2
+ import math
3
+ import tempfile
4
+ import shutil
5
+ import nibabel as nib
6
+ import numpy as np
7
+ from totalsegmentator.python_api import totalsegmentator
8
+ from mosamatic2.core.tasks.task import Task
9
+ from mosamatic2.core.managers.logmanager import LogManager
10
+ from mosamatic2.core.utils import load_dicom
11
+
12
+ LOG = LogManager()
13
+
14
+ TOTAL_SEGMENTATOR_OUTPUT_DIR = os.path.join(tempfile.gettempdir(), 'total_segmentator_output')
15
+ TOTAL_SEGMENTATOR_TASK = 'total'
16
+ Z_DELTA_OFFSETS = {
17
+ 'vertebrae_L3': 0.333,
18
+ 'vertebrae_T4': 0.5,
19
+ }
20
+
21
+
22
+ class SelectSliceFromScansTask(Task):
23
+ INPUTS = ['scans']
24
+ PARAMS = ['vertebra']
25
+
26
+ def __init__(self, inputs, params, output, overwrite):
27
+ super(SelectSliceFromScansTask, self).__init__(inputs, params, output, overwrite)
28
+
29
+ def load_scan_dirs(self):
30
+ scan_dirs = []
31
+ for d in os.listdir(self.input('scans')):
32
+ scan_dir = os.path.join(self.input('scans'), d)
33
+ if os.path.isdir(scan_dir):
34
+ scan_dirs.append(scan_dir)
35
+ return scan_dirs
36
+
37
+ def extract_masks(self, scan_dir):
38
+ os.makedirs(TOTAL_SEGMENTATOR_OUTPUT_DIR, exist_ok=True)
39
+ totalsegmentator(input=scan_dir, output=TOTAL_SEGMENTATOR_OUTPUT_DIR, fast=True)
40
+ # os.system(f'TotalSegmentator -i {scan_dir} -o {TOTAL_SEGMENTATOR_OUTPUT_DIR} --fast')
41
+
42
+ def delete_total_segmentator_output(self):
43
+ if os.path.exists(TOTAL_SEGMENTATOR_OUTPUT_DIR):
44
+ shutil.rmtree(TOTAL_SEGMENTATOR_OUTPUT_DIR)
45
+
46
+ def get_z_delta_offset_for_mask(self, mask_name):
47
+ if mask_name not in Z_DELTA_OFFSETS.keys():
48
+ return None
49
+ return Z_DELTA_OFFSETS[mask_name]
50
+
51
+ def find_slice(self, scan_dir, vertebra):
52
+ if vertebra == 'L3':
53
+ vertebral_level = 'vertebrae_L3'
54
+ elif vertebra == 'T4':
55
+ vertebral_level = 'vertebrae_T4'
56
+ else:
57
+ raise RuntimeError(f'Unknown vertbra {vertebra}. Options are "L3" and "T4"')
58
+ # Find Z-positions DICOM images
59
+ z_positions = {}
60
+ for f in os.listdir(scan_dir):
61
+ f_path = os.path.join(scan_dir, f)
62
+ p = load_dicom(f_path, stop_before_pixels=True)
63
+ if p is not None:
64
+ z_positions[p.ImagePositionPatient[2]] = f_path
65
+ # Find Z-position L3 image
66
+ mask_file = os.path.join(TOTAL_SEGMENTATOR_OUTPUT_DIR, f'{vertebral_level}.nii.gz')
67
+ mask_obj = nib.load(mask_file)
68
+ mask = mask_obj.get_fdata()
69
+ affine_transform = mask_obj.affine
70
+ indexes = np.array(np.where(mask == 1))
71
+ index_min = indexes.min(axis=1)
72
+ index_max = indexes.max(axis=1)
73
+ world_min = nib.affines.apply_affine(affine_transform, index_min)
74
+ world_max = nib.affines.apply_affine(affine_transform, index_max)
75
+ z_direction = affine_transform[:3, 2][2]
76
+ z_sign = math.copysign(1, z_direction)
77
+ z_delta_offset = self.get_z_delta_offset_for_mask(vertebral_level)
78
+ if z_delta_offset is None:
79
+ return None
80
+ z_delta = 0.333 * abs(world_max[2] - world_min[2]) # This needs to be vertebra-specific perhaps
81
+ z_l3 = world_max[2] - z_sign * z_delta
82
+ # Find closest L3 image in DICOM set
83
+ positions = sorted(z_positions.keys())
84
+ closest_file = None
85
+ for z1, z2 in zip(positions[:-1], positions[1:]):
86
+ if min(z1, z2) <= z_l3 <= max(z1, z2):
87
+ closest_z = min(z_positions.keys(), key=lambda z: abs(z - z_l3))
88
+ closest_file = z_positions[closest_z]
89
+ LOG.info(f'Closest image: {closest_file}')
90
+ break
91
+ return closest_file
92
+
93
+ def run(self):
94
+ scan_dirs = self.load_scan_dirs()
95
+ vertebra = self.param('vertebra')
96
+ nr_steps = len(scan_dirs)
97
+ for step in range(nr_steps):
98
+ scan_dir = scan_dirs[step]
99
+ scan_name = os.path.split(scan_dir)[1]
100
+ self.extract_masks(scan_dir)
101
+ file_path = self.find_slice(scan_dir, vertebra)
102
+ if file_path is not None:
103
+ extension = '' if file_path.endswith('.dcm') else '.dcm'
104
+ target_file_path = os.path.join(self.output(), vertebra + '_' + scan_name + extension)
105
+ shutil.copyfile(file_path, target_file_path)
106
+ else:
107
+ LOG.error(f'Could not find slice for vertebral level: {vertebra}')
108
+ self.delete_total_segmentator_output()
109
+ self.set_progress(step, nr_steps)
mosamatic2/core/utils.py CHANGED
@@ -119,10 +119,18 @@ def is_numpy_array(value):
119
119
  return isinstance(value, np.array)
120
120
 
121
121
 
122
- def load_numpy_array(f):
122
+ def is_numpy(f):
123
123
  try:
124
+ np.load(f)
125
+ return True
126
+ except:
127
+ return False
128
+
129
+
130
+ def load_numpy_array(f):
131
+ if is_numpy(f):
124
132
  return np.load(f)
125
- except Exception as e:
133
+ else:
126
134
  return None
127
135
 
128
136
 
mosamatic2/server.py CHANGED
@@ -6,6 +6,7 @@ from mosamatic2.core.tasks import SegmentMuscleFatL3TensorFlowTask
6
6
  from mosamatic2.core.tasks import CalculateScoresTask
7
7
  from mosamatic2.core.tasks import CreatePngsFromSegmentationsTask
8
8
  from mosamatic2.core.tasks import Dicom2NiftiTask
9
+ from mosamatic2.core.tasks import SelectSliceFromScansTask
9
10
 
10
11
  app = Flask(__name__)
11
12
 
@@ -105,6 +106,22 @@ def run_dicom2nifti():
105
106
  return 'PASSED'
106
107
 
107
108
 
109
+ @app.route('/selectslicefromscans')
110
+ def run_selectslicefromscans():
111
+ scans = request.args.get('scans')
112
+ vertebra = request.args.get('vertebra')
113
+ output = request.args.get('output')
114
+ overwrite = request.args.get('overwrite', default=True, type=bool)
115
+ task = SelectSliceFromScansTask(
116
+ inputs={'scans': scans},
117
+ params={'vertebra': vertebra},
118
+ output=output,
119
+ overwrite=overwrite,
120
+ )
121
+ task.run()
122
+ return 'PASSED'
123
+
124
+
108
125
  def main():
109
126
  parser = argparse.ArgumentParser()
110
127
  parser.add_argument('--port', type=int, default=constants.MOSAMATIC2_SERVER_PORT)
@@ -19,6 +19,7 @@ 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.selectslicefromscanstaskpanel import SelectSliceFromScansTaskPanel
22
23
  from mosamatic2.ui.widgets.panels.pipelines.defaultpipelinepanel import DefaultPipelinePanel
23
24
 
24
25
  LOG = LogManager()
@@ -36,6 +37,7 @@ class MainWindow(QMainWindow):
36
37
  self._create_pngs_from_segmentations_task_panel = None
37
38
  self._calculate_scores_task_panel = None
38
39
  self._dicom2nifti_task_panel = None
40
+ self._select_slice_from_scans_task_panel = None
39
41
  self._default_pipeline_panel = None
40
42
  self.init_window()
41
43
 
@@ -75,12 +77,15 @@ class MainWindow(QMainWindow):
75
77
  create_pngs_from_segmentations_task_action.triggered.connect(self.handle_create_pngs_from_segmentations_task_action)
76
78
  dicom2nifti_task_action = QAction('Dicom2NiftiTask', self)
77
79
  dicom2nifti_task_action.triggered.connect(self.handle_dicom2nifti_task_action)
80
+ select_slice_from_scans_task_action = QAction('SelectSliceFromScansTask', self)
81
+ select_slice_from_scans_task_action.triggered.connect(self.handle_select_slice_from_scans_task_action)
78
82
  tasks_menu = self.menuBar().addMenu('Tasks')
79
83
  tasks_menu.addAction(rescale_dicom_images_task_action)
80
84
  tasks_menu.addAction(segment_muscle_fat_l3_tensorflow_task_action)
81
85
  tasks_menu.addAction(calculate_scores_task_action)
82
86
  tasks_menu.addAction(create_pngs_from_segmentations_task_action)
83
87
  tasks_menu.addAction(dicom2nifti_task_action)
88
+ tasks_menu.addAction(select_slice_from_scans_task_action)
84
89
 
85
90
  def init_pipelines_menu(self):
86
91
  default_pipeline_action = QAction('DefaultPipeline', self)
@@ -106,6 +111,7 @@ class MainWindow(QMainWindow):
106
111
  self._main_panel.add_panel(self.create_pngs_from_segmentations_task_panel(), 'createpngsfromsegmentationstaskpanel')
107
112
  self._main_panel.add_panel(self.calculate_scores_task_panel(), 'calculatescorestaskpanel')
108
113
  self._main_panel.add_panel(self.dicom2nifti_task_panel(), 'dicom2niftitaskpanel')
114
+ self._main_panel.add_panel(self.select_slice_from_scans_task_panel(), 'selectslicefromscanstaskpanel')
109
115
  self._main_panel.add_panel(self.default_pipeline_panel(), 'defaultpipelinepanel')
110
116
  self._main_panel.select_panel('defaultpipelinepanel')
111
117
  return self._main_panel
@@ -142,6 +148,11 @@ class MainWindow(QMainWindow):
142
148
  if not self._dicom2nifti_task_panel:
143
149
  self._dicom2nifti_task_panel = Dicom2NiftiTaskPanel()
144
150
  return self._dicom2nifti_task_panel
151
+
152
+ def select_slice_from_scans_task_panel(self):
153
+ if not self._select_slice_from_scans_task_panel:
154
+ self._select_slice_from_scans_task_panel = SelectSliceFromScansTaskPanel()
155
+ return self._select_slice_from_scans_task_panel
145
156
 
146
157
  def default_pipeline_panel(self):
147
158
  if not self._default_pipeline_panel:
@@ -170,6 +181,9 @@ class MainWindow(QMainWindow):
170
181
  def handle_dicom2nifti_task_action(self):
171
182
  self.main_panel().select_panel('dicom2niftitaskpanel')
172
183
 
184
+ def handle_select_slice_from_scans_task_action(self):
185
+ self.main_panel().select_panel('selectslicefromscanstaskpanel')
186
+
173
187
  def handle_default_pipeline_action(self):
174
188
  self.main_panel().select_panel('defaultpipelinepanel')
175
189
 
@@ -184,6 +198,7 @@ class MainWindow(QMainWindow):
184
198
  self.create_pngs_from_segmentations_task_panel().save_inputs_and_parameters()
185
199
  self.calculate_scores_task_panel().save_inputs_and_parameters()
186
200
  self.dicom2nifti_task_panel().save_inputs_and_parameters()
201
+ self.select_slice_from_scans_task_panel().save_inputs_and_parameters()
187
202
  self.default_pipeline_panel().save_inputs_and_parameters()
188
203
  return super().closeEvent(event)
189
204
 
@@ -1 +1 @@
1
- 2.0.4
1
+ 2.0.5
@@ -3,7 +3,7 @@ import os
3
3
  from PySide6.QtWidgets import (
4
4
  QLineEdit,
5
5
  QCheckBox,
6
- QSpinBox,
6
+ QComboBox,
7
7
  QHBoxLayout,
8
8
  QVBoxLayout,
9
9
  QFormLayout,
@@ -16,26 +16,26 @@ from PySide6.QtCore import (
16
16
  Slot,
17
17
  )
18
18
 
19
- from mosamaticdesktop.core.utils.logmanager import LogManager
20
- from mosamaticdesktop.ui.panels.taskpanel import TaskPanel
21
- from mosamaticdesktop.ui.settings import Settings
22
- from mosamaticdesktop.ui.utils import is_macos
23
- from mosamaticdesktop.ui.worker import Worker
24
-
25
- from mosamatic.tasks import SelectSliceFromScanTask
19
+ from mosamatic2.core.managers.logmanager import LogManager
20
+ from mosamatic2.ui.widgets.panels.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 SelectSliceFromScansTask
26
25
 
27
26
  LOG = LogManager()
28
27
 
29
- PANEL_TITLE = 'Automatically select L3 or T4 slice from full CT scan'
30
- PANEL_NAME = 'selectslicefromscantaskpanel'
28
+ PANEL_TITLE = 'Automatically select L3 slice from full CT scan'
29
+ PANEL_NAME = 'selectslicefromscanstaskpanel'
31
30
 
32
31
 
33
- class SelectSliceFromScanTaskPanel(TaskPanel):
32
+ class SelectSliceFromScansTaskPanel(TaskPanel):
34
33
  def __init__(self):
35
- super(SelectSliceFromScanTaskPanel, self).__init__()
34
+ super(SelectSliceFromScansTaskPanel, self).__init__()
36
35
  self.set_title(PANEL_TITLE)
37
36
  self._scans_dir_line_edit = None
38
37
  self._scans_dir_select_button = None
38
+ self._vertebra_combobox = None
39
39
  self._output_dir_line_edit = None
40
40
  self._output_dir_select_button = None
41
41
  self._overwrite_checkbox = None
@@ -58,6 +58,13 @@ class SelectSliceFromScanTaskPanel(TaskPanel):
58
58
  self._scans_dir_select_button.clicked.connect(self.handle_scans_dir_select_button)
59
59
  return self._scans_dir_select_button
60
60
 
61
+ def vertebra_combobox(self):
62
+ if not self._vertebra_combobox:
63
+ self._vertebra_combobox = QComboBox()
64
+ self._vertebra_combobox.addItems(['L3'])
65
+ self._vertebra_combobox.setCurrentText(self.settings().get(f'{PANEL_NAME}/vertebra'))
66
+ return self._vertebra_combobox
67
+
61
68
  def output_dir_line_edit(self):
62
69
  if not self._output_dir_line_edit:
63
70
  self._output_dir_line_edit = QLineEdit(self.settings().get(f'{PANEL_NAME}/output_dir'))
@@ -101,6 +108,7 @@ class SelectSliceFromScanTaskPanel(TaskPanel):
101
108
  output_dir_layout.addWidget(self.output_dir_line_edit())
102
109
  output_dir_layout.addWidget(self.output_dir_select_button())
103
110
  self.form_layout().addRow('Scans directory', scans_dir_layout)
111
+ # self.form_layout().addRow('Vertebra', self.vertebra_combobox())
104
112
  self.form_layout().addRow('Output directory', output_dir_layout)
105
113
  self.form_layout().addRow('Overwrite', self.overwrite_checkbox())
106
114
  layout = QVBoxLayout()
@@ -134,11 +142,11 @@ class SelectSliceFromScanTaskPanel(TaskPanel):
134
142
  LOG.info('Running task...')
135
143
  self.run_task_button().setEnabled(False)
136
144
  self.save_inputs_and_parameters()
137
- self._task = SelectSliceFromScanTask(
138
- self.scans_dir_line_edit().text(),
139
- self.output_dir_line_edit().text(),
140
- 'vertebrae_L3',
141
- self.overwrite_checkbox().isChecked()
145
+ self._task = SelectSliceFromScansTask(
146
+ inputs={'scans': self.scans_dir_line_edit().text()},
147
+ params={'vertebra': 'L3'},
148
+ output=self.output_dir_line_edit().text(),
149
+ overwrite=self.overwrite_checkbox().isChecked(),
142
150
  )
143
151
  self._worker = Worker(self._task)
144
152
  self._thread = QThread()
@@ -180,5 +188,6 @@ class SelectSliceFromScanTaskPanel(TaskPanel):
180
188
 
181
189
  def save_inputs_and_parameters(self):
182
190
  self.settings().set(f'{PANEL_NAME}/scans_dir', self.scans_dir_line_edit().text())
191
+ self.settings().set(f'{PANEL_NAME}/vertebra', self.vertebra_combobox().currentText())
183
192
  self.settings().set(f'{PANEL_NAME}/output_dir', self.output_dir_line_edit().text())
184
193
  self.settings().set(f'{PANEL_NAME}/overwrite', self.overwrite_checkbox().isChecked())
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: mosamatic2
3
- Version: 2.0.4
3
+ Version: 2.0.5
4
4
  Summary:
5
5
  Author: Ralph Brecheisen
6
6
  Author-email: r.brecheisen@maastrichtuniversity.nl
@@ -1,13 +1,14 @@
1
1
  models.py,sha256=Kx6oWKt7IpTTxrhBDrX61X-ZX12J7yPkJFuhVDsDHoQ,8807
2
2
  mosamatic2/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  mosamatic2/app.py,sha256=RIUa5tvMYFcmEII4xZPLZZdx9dXWqBvwkxkl_R97Jkw,860
4
- mosamatic2/cli.py,sha256=bVd2zf7CYpVIc-zRweWgRO7jOPZi68JhnnDBuq-L43E,1201
4
+ mosamatic2/cli.py,sha256=RTogXBXiYW_EDTmnX7TXx2T22Yth_1AwLFiJP2IUDMc,1289
5
5
  mosamatic2/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
6
  mosamatic2/commands/calculatescores.py,sha256=Lb8Q8L2yq7Tt6VBJ6_lltRuldrev_pac6fcgF-xzZyE,1984
7
7
  mosamatic2/commands/createpngsfromsegmentations.py,sha256=uUAQJVTqOkBCfENzi21RBNYvf6_nuesx1MeR3j_-7dM,1682
8
8
  mosamatic2/commands/dicom2nifti.py,sha256=4hMvglxdOid7p7P_Jc-Tudsf93JRMlYaQsEQctLq2d4,1015
9
9
  mosamatic2/commands/rescaledicomimages.py,sha256=25QdCzB5s0sRwkTb3o5zco2bIwy6LttNf7i97kGBDYQ,1280
10
10
  mosamatic2/commands/segmentmusclefatl3tensorflow.py,sha256=CdScmA_EQicaN4GY5bBUOYwfhDPqy9om2sxY3WrtmM0,1424
11
+ mosamatic2/commands/selectslicefromscans.py,sha256=3398PM2uBcxF6wpb0-c-Itp_qxoAxBf0SE2nDDI3Ct4,1715
11
12
  mosamatic2/constants.py,sha256=MVYMwO-x2jQSN37o3zNkRseVQ1nYRA3mLv3v_Q0Mlds,1284
12
13
  mosamatic2/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
14
  mosamatic2/core/data/__init__.py,sha256=j9iGqUTJlGF0N0gPrzzpe_Dhv0Bj9c6FdQ1g7U-_j2g,298
@@ -16,6 +17,8 @@ mosamatic2/core/data/dicomimageseries.py,sha256=OZkNi15crL8nEA-PGYsM0k9NMi2mMHRv
16
17
  mosamatic2/core/data/dixonseries.py,sha256=kq9fy65MSM2XwiScqp7b3rQ09JmpyGwbG6ldZsuPRrM,516
17
18
  mosamatic2/core/data/filedata.py,sha256=hCnpizGqOpxzIADJkDS2_NSmKVLL1u49TYjSJE5UXQo,515
18
19
  mosamatic2/core/data/multidicomimage.py,sha256=cdd0H4Dq49h7NLKBx51_h_HZVnH7-reu48PY8m6tXwU,1034
20
+ mosamatic2/core/data/multinumpyimage.py,sha256=MU5_ec00vx9_JhkibgkcgyGFfaj69STy85ifa8MNsSc,753
21
+ mosamatic2/core/data/numpyimage.py,sha256=ZbJ9JRAVOgvXzTZ6kscEuGZJqKT-MPdt42IAlmh3iXo,359
19
22
  mosamatic2/core/managers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
23
  mosamatic2/core/managers/logmanager.py,sha256=NEaXvhl0aILjBbK710GaWanVuuNvB51HpHhE5rgYvng,1391
21
24
  mosamatic2/core/managers/logmanagerlistener.py,sha256=Gaig07yjBnyQq9I8sN85olTEeDCDyCFQnEJdwzvmgvc,99
@@ -23,9 +26,9 @@ mosamatic2/core/pipelines/__init__.py,sha256=MXoylu34AlcyudJpjuLa4B7K9gZmxLnZGDa
23
26
  mosamatic2/core/pipelines/defaultpipeline.py,sha256=EUblRhLZXhslz9bdBmx8v9yjpgOdsHviqQZ5elK8gNQ,2901
24
27
  mosamatic2/core/pipelines/pipeline.py,sha256=mRxKXLKwgKDpc8R9mCI6gDKGJ2lKVxRQ__Sf0Mfn_Qc,384
25
28
  mosamatic2/core/singleton.py,sha256=FV0k_LlOCmFhlWN6gf1c2x7YXWyd8-7DsIMvOKrI6NY,224
26
- mosamatic2/core/tasks/__init__.py,sha256=3bWBH2Q5X44_k7s3wei7AHm86MLEqoySyxSN7UKuqRs,545
29
+ mosamatic2/core/tasks/__init__.py,sha256=az_IatVtpT7M2AiOl7ez6EW_oR7_n9GtC1nL0_mYwZk,655
27
30
  mosamatic2/core/tasks/calculatescorestask/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
- mosamatic2/core/tasks/calculatescorestask/calculatescorestask.py,sha256=1CUJK9IsePBbEuF3-0LnZp1sWMxPDiJaNy0a-8DaTUE,6576
31
+ mosamatic2/core/tasks/calculatescorestask/calculatescorestask.py,sha256=jEbogrEnEtMbmfQ8KOGSUdGMhdeX69Bv01-82faRIlY,6617
29
32
  mosamatic2/core/tasks/createpngsfromsegmentationstask/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
33
  mosamatic2/core/tasks/createpngsfromsegmentationstask/createpngsfromsegmentationstask.py,sha256=1UpOsp1CH668BQ0g4tALou_tFgisC306VcvqOKSDuTo,1884
31
34
  mosamatic2/core/tasks/dicom2niftitask/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -34,17 +37,19 @@ mosamatic2/core/tasks/rescaledicomimagestask/__init__.py,sha256=47DEQpj8HBSa-_TI
34
37
  mosamatic2/core/tasks/rescaledicomimagestask/rescaledicomimagestask.py,sha256=vGSpMJoXFtE-IHGxTEO9DMkerMJcfG5r9tXgtvkxm6Y,3053
35
38
  mosamatic2/core/tasks/segmentmusclefatl3tensorflowtask/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
39
  mosamatic2/core/tasks/segmentmusclefatl3tensorflowtask/paramloader.py,sha256=VxTCOYK_1VRAG83P-ulm0LPvqXI-0iT5BCr0Rdr7MWg,900
37
- mosamatic2/core/tasks/segmentmusclefatl3tensorflowtask/segmentmusclefatl3tensorflowtask.py,sha256=bDRG9phYSF4o4mFsdJhyJ613CqOixFPTd5yL2gBFSPY,5351
40
+ mosamatic2/core/tasks/segmentmusclefatl3tensorflowtask/segmentmusclefatl3tensorflowtask.py,sha256=E3GHzGtl-v_qIdLjSy3cbDnf8vfWK6Bax3RAZcKCqXg,5149
41
+ mosamatic2/core/tasks/selectslicefromscanstask/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
42
+ mosamatic2/core/tasks/selectslicefromscanstask/selectslicefromscanstask.py,sha256=1a_QHcIdS4VB39cNEBniaaDzUx3k8DcR0wCtdr8G1d0,4586
38
43
  mosamatic2/core/tasks/task.py,sha256=APPnid6dpSGkPuDqU1vm2RIMR5vkpvbP1CPHUMjympg,1691
39
- mosamatic2/core/utils.py,sha256=RHBcvrUshese6NG_OigO4ZGGR3iCOmmeDJjgPnLpaBo,10753
40
- mosamatic2/server.py,sha256=UDALqk_TZ5Vz7ZOjzhV2-7-kHIPM-_OKXFV7lf2R1t0,3617
44
+ mosamatic2/core/utils.py,sha256=zh44FNOWxNKuZ4FcM7VIfMvdlzOr4AA8_PJ1r-6_83k,10855
45
+ mosamatic2/server.py,sha256=jiUc7-aFaDMSY2hg6BhMC9C2FU4V2OrMBSoiIAP8Zcs,4158
41
46
  mosamatic2/ui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
42
- mosamatic2/ui/mainwindow.py,sha256=efmZAC5vYEdCg5bw1ixrcACzYN2xe15xyrNwnXersyI,10100
47
+ mosamatic2/ui/mainwindow.py,sha256=k5yxHTjwvpwXXWx94sJ45q1BcH-06B9I7Qnqfd1Zbr8,11119
43
48
  mosamatic2/ui/resources/icons/mosamatic2.icns,sha256=OfhC-diJTIgaNMOezxKKilGsY7mRkaGdU5dGr0MOjIA,2994125
44
49
  mosamatic2/ui/resources/icons/mosamatic2.ico,sha256=ySD3RYluHK3pgS0Eas7eKrVk_AskdLQ4qs_IT-wNhq4,12229
45
50
  mosamatic2/ui/resources/icons/spinner.gif,sha256=rvaac6GUZauHSPFSOLWr0RmLfjmtZih2Q8knQ2WP3Po,16240
46
51
  mosamatic2/ui/resources/images/body-composition.jpg,sha256=KD-BudbXwThB4lJOZZN-ad5-TZRaaZ5cKTH0Ar1TOZs,21227
47
- mosamatic2/ui/resources/VERSION,sha256=CxHeq1Bk1fry3nkuFpVDAvnw27-hr4X2onfG3ZD1M6U,8
52
+ mosamatic2/ui/resources/VERSION,sha256=I2Qe9unc-Hx4iKTROuxBK26Iy4oCUcMjfIY6KzAtKAY,8
48
53
  mosamatic2/ui/settings.py,sha256=YEVHYJIfNsqMO3v1pjzgh7Pih9GGoUX7S9s8S-sBNUk,2121
49
54
  mosamatic2/ui/utils.py,sha256=6bbPIrh4RJ_yhQKNZrgPbL4XeUEogjIjbk_e5c3QS5g,853
50
55
  mosamatic2/ui/widgets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -65,10 +70,10 @@ mosamatic2/ui/widgets/panels/tasks/createpngsfromsegmentationstaskpanel.py,sha25
65
70
  mosamatic2/ui/widgets/panels/tasks/dicom2niftitaskpanel.py,sha256=mb5LxDuhkwA08LcHGigul7xmef_wTGrmr-DZ72O_joc,7474
66
71
  mosamatic2/ui/widgets/panels/tasks/rescaledicomimagestaskpanel.py,sha256=_K-XM4zvzq_AMugLqN4p87iEsfX594qYSVnfjNlmAfU,7591
67
72
  mosamatic2/ui/widgets/panels/tasks/segmentmusclefatl3tensorflowtaskpanel.py,sha256=pLEpUXx_vi6PfOykAwp95m5yLRrIvdF_XaupHBOW31U,9624
68
- mosamatic2/ui/widgets/panels/tasks/selectslicefromscantaskpanel.py,sha256=Q5txmTPssKEQpy_yc-iKCN22K5h3B_7WzPP885uP79Q,7506
73
+ mosamatic2/ui/widgets/panels/tasks/selectslicefromscanstaskpanel.py,sha256=ysIoX_IHTPBfEhJQkdM54S3ZL24IAeA8A_ldzgr8BwU,8071
69
74
  mosamatic2/ui/widgets/splashscreen.py,sha256=MS-OczOWfwwEQNQd-JWe9_Mh57css0cSQgbu973rwQo,4056
70
75
  mosamatic2/ui/worker.py,sha256=v7e3gq7MUudgpB1BJW-P7j5wurzu6-HG5m7I6WHgJp0,699
71
- mosamatic2-2.0.4.dist-info/entry_points.txt,sha256=MCUpKkgbej1clgp8EqlLQGs0BIKwGPcBPiVWLfGz9Gw,126
72
- mosamatic2-2.0.4.dist-info/METADATA,sha256=89x_i4kNHoZwtq3qBwy5QPOHC-ljsHJsntQDCh5km50,1402
73
- mosamatic2-2.0.4.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
74
- mosamatic2-2.0.4.dist-info/RECORD,,
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,,