mosamatic2 2.0.11__py3-none-any.whl → 2.0.13__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 (26) hide show
  1. mosamatic2/cli.py +4 -0
  2. mosamatic2/commands/boadockerpipeline.py +48 -0
  3. mosamatic2/commands/defaultdockerpipeline.py +73 -0
  4. mosamatic2/commands/dicom2nifti.py +18 -9
  5. mosamatic2/core/data/multiniftiimage.py +26 -0
  6. mosamatic2/core/data/multinumpyimage.py +4 -4
  7. mosamatic2/core/data/niftiimage.py +13 -0
  8. mosamatic2/core/data/numpyimage.py +1 -1
  9. mosamatic2/core/pipelines/__init__.py +2 -1
  10. mosamatic2/core/pipelines/boadockerpipeline/__init__.py +0 -0
  11. mosamatic2/core/pipelines/boadockerpipeline/boadockerpipeline.py +70 -0
  12. mosamatic2/core/pipelines/defaultdockerpipeline/defaultdockerpipeline.py +5 -12
  13. mosamatic2/core/tasks/calculatescorestask/calculatescorestask.py +2 -2
  14. mosamatic2/core/tasks/dicom2niftitask/dicom2niftitask.py +27 -10
  15. mosamatic2/core/tasks/segmentmusclefatl3tensorflowtask/segmentmusclefatl3tensorflowtask.py +3 -0
  16. mosamatic2/core/tasks/selectslicefromscanstask/selectslicefromscanstask.py +1 -1
  17. mosamatic2/core/utils.py +27 -3
  18. mosamatic2/ui/mainwindow.py +15 -0
  19. mosamatic2/ui/resources/VERSION +1 -1
  20. mosamatic2/ui/widgets/panels/pipelines/boadockerpipelinepanel.py +185 -0
  21. mosamatic2/ui/widgets/panels/pipelines/defaultdockerpipelinepanel.py +0 -14
  22. mosamatic2/ui/widgets/panels/tasks/dicom2niftitaskpanel.py +23 -23
  23. {mosamatic2-2.0.11.dist-info → mosamatic2-2.0.13.dist-info}/METADATA +2 -1
  24. {mosamatic2-2.0.11.dist-info → mosamatic2-2.0.13.dist-info}/RECORD +26 -19
  25. {mosamatic2-2.0.11.dist-info → mosamatic2-2.0.13.dist-info}/WHEEL +0 -0
  26. {mosamatic2-2.0.11.dist-info → mosamatic2-2.0.13.dist-info}/entry_points.txt +0 -0
mosamatic2/cli.py CHANGED
@@ -8,6 +8,8 @@ from mosamatic2.commands import (
8
8
  selectslicefromscans,
9
9
  createdicomsummary,
10
10
  defaultpipeline,
11
+ defaultdockerpipeline,
12
+ boadockerpipeline,
11
13
  )
12
14
  from mosamatic2.core.utils import show_doc_command
13
15
 
@@ -37,4 +39,6 @@ main.add_command(dicom2nifti.dicom2nifti)
37
39
  main.add_command(selectslicefromscans.selectslicefromscans)
38
40
  main.add_command(createdicomsummary.createdicomsummary)
39
41
  main.add_command(defaultpipeline.defaultpipeline)
42
+ main.add_command(defaultdockerpipeline.defaultdockerpipeline)
43
+ main.add_command(boadockerpipeline.boadockerpipeline)
40
44
  main.add_command(show_doc_command(main)) # Special command to show long description for command
@@ -0,0 +1,48 @@
1
+ import click
2
+
3
+ from mosamatic2.core.pipelines import BoaDockerPipeline
4
+
5
+
6
+ @click.command(help='Runs 3D body composition analysis pipeline using BOA algorithm')
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
+ '--output',
15
+ required=True,
16
+ type=click.Path(),
17
+ help='Output directory (no spaces allowed)'
18
+ )
19
+ @click.option(
20
+ '--overwrite',
21
+ type=click.BOOL,
22
+ default=False,
23
+ help='Overwrite [true|false]'
24
+ )
25
+ def boadockerpipeline(scans, output, overwrite):
26
+ """
27
+ Runs 3D body composition analysis pipeline using BOA algorithm.
28
+
29
+ Parameters
30
+ ----------
31
+ --scans : str
32
+ Root directory with scan directories for each patient. Each scan directory should
33
+ contain DICOM images for a single scan only and nothing else. Also, the directory
34
+ paths cannot contain any spaces.
35
+
36
+ --output : str
37
+ Path to output directory. No spaces allowed.
38
+
39
+ --overwrite : bool
40
+ Overwrite contents output directory [true|false]
41
+ """
42
+ pipeline = BoaDockerPipeline(
43
+ inputs={'scans': scans},
44
+ params=None,
45
+ output=output,
46
+ overwrite=overwrite,
47
+ )
48
+ pipeline.run()
@@ -0,0 +1,73 @@
1
+ import click
2
+
3
+ from mosamatic2.core.pipelines import DefaultDockerPipeline
4
+
5
+
6
+ @click.command(help='Runs default L3 analysis pipeline through Docker')
7
+ @click.option(
8
+ '--images',
9
+ required=True,
10
+ type=click.Path(exists=True),
11
+ help='Directory with L3 images (no spaces allowed)',
12
+ )
13
+ @click.option(
14
+ '--model_files',
15
+ required=True,
16
+ type=click.Path(),
17
+ help='Input directory with AI model files (no spaces allowed)'
18
+ )
19
+ @click.option(
20
+ '--output',
21
+ required=True,
22
+ type=click.Path(),
23
+ help='Output directory (no spaces allowed)'
24
+ )
25
+ @click.option(
26
+ '--overwrite',
27
+ type=click.BOOL,
28
+ default=False,
29
+ help='Overwrite [true|false]'
30
+ )
31
+ def defaultdockerpipeline(images, model_files, output, overwrite):
32
+ """
33
+ Runs default L3 analysis pipeline through Docker
34
+
35
+ Parameters
36
+ ----------
37
+ --images : str
38
+ Directory with L3 images. Warning: This directory path cannot contain any spaces!
39
+ Docker has issues working with that.
40
+
41
+ --model_files : str
42
+ Directory with AI model files. This directory can ONLY contain the following
43
+ files:
44
+
45
+ (1) contour_model-1.0.zip
46
+ (2) model-1.0.zip
47
+ (3) params-1.0.json
48
+
49
+ These files can be downloaded from:
50
+ https://mosamatic.rbeesoft.nl/wordpress/mosamatic/installation/
51
+
52
+ Warning: This directory path cannot contain any spaces!
53
+
54
+ --output : str
55
+ Path to output directory (no spaces!)
56
+
57
+ --overwrite : bool
58
+ Overwrite contents output directory [true|false]
59
+ """
60
+ pipeline = DefaultDockerPipeline(
61
+ inputs={'images': images, 'model_files': model_files},
62
+ params={
63
+ 'target_size': 512,
64
+ 'model_type': 'tensorflow',
65
+ 'model_version': 1.0,
66
+ 'file_type': 'npy',
67
+ 'fig_width': 10,
68
+ 'fig_height': 10,
69
+ },
70
+ output=output,
71
+ overwrite=overwrite,
72
+ )
73
+ pipeline.run()
@@ -3,12 +3,18 @@ import click
3
3
  from mosamatic2.core.tasks import Dicom2NiftiTask
4
4
 
5
5
 
6
- @click.command(help='Converts DICOM series to NIFTI')
6
+ @click.command(help='Converts root directory with DICOM series to NIFTI format')
7
7
  @click.option(
8
- '--images',
8
+ '--scans',
9
9
  required=True,
10
10
  type=click.Path(exists=True),
11
- help='Directory with images',
11
+ help='Root directory with DICOM scans (one for each patient)',
12
+ )
13
+ @click.option(
14
+ '--compressed',
15
+ type=click.BOOL,
16
+ default=True,
17
+ help='Compress with gzip [true|false] (default: True)'
12
18
  )
13
19
  @click.option(
14
20
  '--output',
@@ -22,14 +28,17 @@ from mosamatic2.core.tasks import Dicom2NiftiTask
22
28
  default=False,
23
29
  help='Overwrite [true|false]'
24
30
  )
25
- def dicom2nifti(images, output, overwrite):
31
+ def dicom2nifti(scans, compressed, output, overwrite):
26
32
  """
27
- Converts single DICOM series (scan) to NIFTI
33
+ Converts DICOM scans to NIFTI format.
28
34
 
29
35
  Parameters
30
36
  ----------
31
- --images : str
32
- Directory with DICOM images of a single series
37
+ --scans : str
38
+ Root directory with DICOM scans (one subdirectory for each patient)
39
+
40
+ --compressed : bool
41
+ Whether to compress the NIFTI file with gzip or not (default: True)
33
42
 
34
43
  --output : str
35
44
  Path to output directory
@@ -38,8 +47,8 @@ def dicom2nifti(images, output, overwrite):
38
47
  Overwrite contents output directory [true|false]
39
48
  """
40
49
  task = Dicom2NiftiTask(
41
- inputs={'images': images},
42
- params=None,
50
+ inputs={'scans': scans},
51
+ params={'compressed': compressed},
43
52
  output=output,
44
53
  overwrite=overwrite,
45
54
  )
@@ -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.niftiimage import NiftiImage
5
+
6
+ LOG = LogManager()
7
+
8
+
9
+ class MultiNiftiImage(FileData):
10
+ def __init__(self):
11
+ super(MultiNiftiImage, 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 = NiftiImage()
22
+ image.set_path(f_path)
23
+ if image.load():
24
+ self._images.append(image)
25
+ return True
26
+ return False
@@ -1,14 +1,14 @@
1
1
  import os
2
2
  from mosamatic2.core.managers.logmanager import LogManager
3
3
  from mosamatic2.core.data.filedata import FileData
4
- from mosamatic2.core.data.numpyimage import NumPyImage
4
+ from mosamatic2.core.data.numpyimage import NumpyImage
5
5
 
6
6
  LOG = LogManager()
7
7
 
8
8
 
9
- class MultiNumPyImage(FileData):
9
+ class MultiNumpyImage(FileData):
10
10
  def __init__(self):
11
- super(MultiNumPyImage, self).__init__()
11
+ super(MultiNumpyImage, self).__init__()
12
12
  self._images = []
13
13
 
14
14
  def images(self):
@@ -18,7 +18,7 @@ class MultiNumPyImage(FileData):
18
18
  if self.path():
19
19
  for f in os.listdir(self.path()):
20
20
  f_path = os.path.join(self.path(), f)
21
- image = NumPyImage()
21
+ image = NumpyImage()
22
22
  image.set_path(f_path)
23
23
  if image.load():
24
24
  self._images.append(image)
@@ -0,0 +1,13 @@
1
+ from mosamatic2.core.data.filedata import FileData
2
+ from mosamatic2.core.utils import (
3
+ is_nifti,
4
+ load_nifti,
5
+ )
6
+
7
+ class NiftiImage(FileData):
8
+ def load(self):
9
+ if self.path():
10
+ if is_nifti(self.path()):
11
+ self.set_object(load_nifti(self.path()))
12
+ return True
13
+ return False
@@ -4,7 +4,7 @@ from mosamatic2.core.utils import (
4
4
  load_numpy_array,
5
5
  )
6
6
 
7
- class NumPyImage(FileData):
7
+ class NumpyImage(FileData):
8
8
  def load(self):
9
9
  if self.path():
10
10
  if is_numpy(self.path()):
@@ -1,2 +1,3 @@
1
1
  from mosamatic2.core.pipelines.defaultpipeline.defaultpipeline import DefaultPipeline
2
- from mosamatic2.core.pipelines.defaultdockerpipeline.defaultdockerpipeline import DefaultDockerPipeline
2
+ from mosamatic2.core.pipelines.defaultdockerpipeline.defaultdockerpipeline import DefaultDockerPipeline
3
+ from mosamatic2.core.pipelines.boadockerpipeline.boadockerpipeline import BoaDockerPipeline
@@ -0,0 +1,70 @@
1
+ import os
2
+ from mosamatic2.core.pipelines.pipeline import Pipeline
3
+ from mosamatic2.core.tasks import Dicom2NiftiTask
4
+ from mosamatic2.core.managers.logmanager import LogManager
5
+ from mosamatic2.core.utils import (
6
+ is_docker_running,
7
+ to_unix_path,
8
+ current_time_in_seconds,
9
+ elapsed_time_in_seconds,
10
+ duration,
11
+ )
12
+
13
+ LOG = LogManager()
14
+
15
+
16
+ class BoaDockerPipeline(Pipeline):
17
+ INPUTS = ['scans']
18
+ PARAMS = []
19
+
20
+ def __init__(self, inputs, params, output, overwrite):
21
+ super(BoaDockerPipeline, self).__init__(inputs, params, output, overwrite)
22
+
23
+ def load_nifti_files(self):
24
+ nifti_files_dir = os.path.join(self.output(), 'dicom2niftitask')
25
+ nifti_files = []
26
+ for f in os.listdir(nifti_files_dir):
27
+ f_path = os.path.join(nifti_files_dir, f)
28
+ if f.endswith('.nii') or f.endswith('.nii.gz'):
29
+ nifti_files.append(f_path)
30
+ return nifti_files
31
+
32
+ def run(self):
33
+ assert is_docker_running()
34
+ # First convert DICOM series to NIFTI format
35
+ dicom2nifti_task = Dicom2NiftiTask(
36
+ inputs={'scans': self.input('scans')},
37
+ params={'compressed': True},
38
+ output=self.output(),
39
+ overwrite=self.overwrite(),
40
+ )
41
+ dicom2nifti_task.run()
42
+ # Load NIFTI file paths
43
+ nifti_files = self.load_nifti_files()
44
+ workspaces_dir = to_unix_path(os.path.join(self.output(), 'workspaces'))
45
+ os.makedirs(workspaces_dir, exist_ok=True)
46
+ weights_dir = to_unix_path(os.path.join(self.output(), 'weights'))
47
+ start_time = current_time_in_seconds()
48
+ for f in nifti_files:
49
+ start_time_f = current_time_in_seconds()
50
+ f = to_unix_path(f)
51
+ dir_name = os.path.split(f)[1][:-7]
52
+ workspace = to_unix_path(os.path.join(workspaces_dir, dir_name))
53
+ # Build Docker script
54
+ docker_script = 'docker run --rm ' + \
55
+ '-v "{}":/image.nii.gz '.format(f) + \
56
+ '-v "{}":/workspace '.format(workspace) + \
57
+ '-v "{}":/app/weights '.format(weights_dir) + \
58
+ '--gpus all ' + \
59
+ '--network host ' + \
60
+ '--shm-size=8g --ulimit memlock=-1 --ulimit stack=67108864 ' + \
61
+ '--entrypoint /bin/sh ' + \
62
+ 'shipai/boa-cli -c ' + \
63
+ '"python body_organ_analysis --input-image /image.nii.gz --output-dir /workspace/ --models all --verbose"'
64
+ LOG.info(f'Running BOA Docker script: {docker_script}')
65
+ # Run Docker script
66
+ os.system(docker_script)
67
+ elapsed_f = elapsed_time_in_seconds(start_time_f)
68
+ LOG.info(f'Elapsed {dir_name}: {duration(elapsed_f)}')
69
+ elapsed_total = elapsed_time_in_seconds(start_time)
70
+ LOG.info(f'Elapsed total: {duration(elapsed_total)}')
@@ -1,17 +1,9 @@
1
1
  import os
2
-
3
2
  from mosamatic2.core.pipelines.pipeline import Pipeline
4
3
  from mosamatic2.core.managers.logmanager import LogManager
4
+ from mosamatic2.core.utils import is_docker_running, to_unix_path
5
5
 
6
6
  LOG = LogManager()
7
- DOCKER_SCRIPT = """
8
- docker run --rm ^
9
- -v "%IMAGES%":/data/images ^
10
- -v "%MODEL_FILES%":/data/model_files ^
11
- -v "%OUTPUT%":/data/output ^
12
- brecheisen/mosamatic2-cli:%VERSION% defaultpipeline ^
13
- --images /data/images --model_files /data/model_files --output /data/output --overwrite true
14
- """
15
7
 
16
8
 
17
9
  class DefaultDockerPipeline(Pipeline):
@@ -32,10 +24,11 @@ class DefaultDockerPipeline(Pipeline):
32
24
  super(DefaultDockerPipeline, self).__init__(inputs, params, output, overwrite)
33
25
 
34
26
  def run(self):
27
+ assert is_docker_running()
35
28
  docker_script = 'docker run --rm ' + \
36
- '-v "{}":/data/images '.format(self.input('images')) + \
37
- '-v "{}":/data/model_files '.format(self.input('model_files')) + \
38
- '-v "{}":/data/output '.format(self.output()) + \
29
+ '-v "{}":/data/images '.format(to_unix_path(self.input('images'))) + \
30
+ '-v "{}":/data/model_files '.format(to_unix_path(self.input('model_files'))) + \
31
+ '-v "{}":/data/output '.format(to_unix_path(self.output())) + \
39
32
  'brecheisen/mosamatic2-cli:{} defaultpipeline '.format(self.param('version')) + \
40
33
  '--images /data/images --model_files /data/model_files --output /data/output --overwrite true'
41
34
  LOG.info(f'Running Docker script: {docker_script}')
@@ -4,7 +4,7 @@ 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
+ from mosamatic2.core.data.numpyimage import NumpyImage
8
8
  from mosamatic2.core.utils import (
9
9
  get_pixels_from_dicom_object,
10
10
  calculate_area,
@@ -74,7 +74,7 @@ class CalculateScoresTask(Task):
74
74
 
75
75
  def load_segmentation(self, f, file_type='npy'):
76
76
  if file_type == 'npy':
77
- segmentation = NumPyImage()
77
+ segmentation = NumpyImage()
78
78
  segmentation.set_path(f)
79
79
  if segmentation.load():
80
80
  return segmentation.object()
@@ -2,23 +2,40 @@ import os
2
2
  import dicom2nifti
3
3
  from mosamatic2.core.tasks.task import Task
4
4
  from mosamatic2.core.managers.logmanager import LogManager
5
+ from mosamatic2.core.utils import is_dicom
5
6
 
6
7
  LOG = LogManager()
7
8
 
8
9
 
9
10
  class Dicom2NiftiTask(Task):
10
- INPUTS = ['images']
11
- PARAMS = []
11
+ INPUTS = ['scans']
12
+ PARAMS = ['compressed']
12
13
 
13
14
  def __init__(self, inputs, params, output, overwrite):
14
15
  super(Dicom2NiftiTask, self).__init__(inputs, params, output, overwrite)
15
16
 
17
+ def load_scan_dirs(self):
18
+ scan_dirs = []
19
+ for d in os.listdir(self.input('scans')):
20
+ scan_dir = os.path.join(self.input('scans'), d)
21
+ if os.path.isdir(scan_dir):
22
+ scan_dirs.append(scan_dir)
23
+ return scan_dirs
24
+
16
25
  def run(self):
17
- nifti_file_name = os.path.split(self.input('images'))[1] + '.nii.gz'
18
- LOG.info(f'Converting DICOM directory to {nifti_file_name}')
19
- dicom2nifti.dicom_series_to_nifti(
20
- self.input('images'),
21
- os.path.join(self.output(), nifti_file_name),
22
- reorient_nifti=True,
23
- )
24
- self.set_progress(0, 1)
26
+ scan_dirs = self.load_scan_dirs()
27
+ nr_steps = len(scan_dirs)
28
+ for step in range(nr_steps):
29
+ scan_dir = scan_dirs[step]
30
+ scan_name = os.path.split(scan_dir)[1]
31
+ if self.param('compressed'):
32
+ nifti_file_name = scan_name + '.nii.gz'
33
+ else:
34
+ nifti_file_name = scan_name + '.nii'
35
+ LOG.info(f'Converting DICOM series in {scan_dir} to {nifti_file_name}')
36
+ dicom2nifti.dicom_series_to_nifti(
37
+ scan_dir,
38
+ os.path.join(self.output(), nifti_file_name),
39
+ reorient_nifti=True,
40
+ )
41
+ self.set_progress(step, nr_steps)
@@ -9,6 +9,7 @@ from mosamatic2.core.tasks.task import Task
9
9
  from mosamatic2.core.tasks.segmentmusclefatl3tensorflowtask.paramloader import ParamLoader
10
10
  from mosamatic2.core.data.multidicomimage import MultiDicomImage
11
11
  from mosamatic2.core.data.dicomimage import DicomImage
12
+ from mosamatic2.core.managers.logmanager import LogManager
12
13
  from mosamatic2.core.utils import (
13
14
  normalize_between,
14
15
  get_pixels_from_dicom_object,
@@ -16,6 +17,8 @@ from mosamatic2.core.utils import (
16
17
  )
17
18
 
18
19
  DEVICE = 'cpu'
20
+ L3_INDEX = 167
21
+ LOG = LogManager()
19
22
 
20
23
 
21
24
  class SegmentMuscleFatL3TensorFlowTask(Task):
@@ -30,7 +30,7 @@ class SelectSliceFromScansTask(Task):
30
30
  os.makedirs(self._error_dir, exist_ok=True)
31
31
  self._error_file = os.path.join(self._error_dir, 'errors.txt')
32
32
  with open(self._error_file, 'w') as f:
33
- f.write('Errors:\n')
33
+ f.write('Errors:\n\n')
34
34
  LOG.info(f'Error directory: {self._error_dir}')
35
35
 
36
36
  def write_error(self, message):
mosamatic2/core/utils.py CHANGED
@@ -5,6 +5,7 @@ import textwrap
5
5
  import math
6
6
  import pendulum
7
7
  import numpy as np
8
+ import nibabel as nb
8
9
  import struct
9
10
  import binascii
10
11
  import pydicom
@@ -134,6 +135,16 @@ def is_jpeg2000_compressed(p):
134
135
  return False
135
136
 
136
137
 
138
+ def is_nifti(f):
139
+ return f.endswith('.nii') or f.endswith('.nii.gz')
140
+
141
+
142
+ def load_nifti(f):
143
+ if is_nifti(f):
144
+ return nb.load(f)
145
+ return None
146
+
147
+
137
148
  def is_numpy_array(value):
138
149
  return isinstance(value, np.array)
139
150
 
@@ -149,8 +160,7 @@ def is_numpy(f):
149
160
  def load_numpy_array(f):
150
161
  if is_numpy(f):
151
162
  return np.load(f)
152
- else:
153
- return None
163
+ return None
154
164
 
155
165
 
156
166
  def get_pixels_from_tag_file(tag_file_path):
@@ -340,4 +350,18 @@ def convert_numpy_array_to_png_image(
340
350
  png_file_name += '.png'
341
351
  png_file_path = os.path.join(output_dir_path, png_file_name)
342
352
  image.save(png_file_path)
343
- return png_file_path
353
+ return png_file_path
354
+
355
+
356
+ def is_docker_running():
357
+ import docker
358
+ try:
359
+ client = docker.from_env()
360
+ client.ping()
361
+ return True
362
+ except Exception:
363
+ return False
364
+
365
+
366
+ def to_unix_path(path):
367
+ return path.replace("\\", "/").replace(" ", "\\ ")
@@ -23,6 +23,7 @@ from mosamatic2.ui.widgets.panels.tasks.createdicomsummarytaskpanel import Creat
23
23
  from mosamatic2.ui.widgets.panels.tasks.selectslicefromscanstaskpanel import SelectSliceFromScansTaskPanel
24
24
  from mosamatic2.ui.widgets.panels.pipelines.defaultpipelinepanel import DefaultPipelinePanel
25
25
  from mosamatic2.ui.widgets.panels.pipelines.defaultdockerpipelinepanel import DefaultDockerPipelinePanel
26
+ from mosamatic2.ui.widgets.panels.pipelines.boadockerpipelinepanel import BoaDockerPipelinePanel
26
27
  from mosamatic2.ui.widgets.panels.visualizations.slicevisualization.slicevisualization import SliceVisualization
27
28
 
28
29
  LOG = LogManager()
@@ -44,6 +45,7 @@ class MainWindow(QMainWindow):
44
45
  self._select_slice_from_scans_task_panel = None
45
46
  self._default_pipeline_panel = None
46
47
  self._default_docker_pipeline_panel = None
48
+ self._boa_docker_pipeline_panel = None
47
49
  self._slice_visualization = None
48
50
  self.init_window()
49
51
 
@@ -102,9 +104,12 @@ class MainWindow(QMainWindow):
102
104
  default_pipeline_action.triggered.connect(self.handle_default_pipeline_action)
103
105
  default_docker_pipeline_action = QAction('DefaultDockerPipeline', self)
104
106
  default_docker_pipeline_action.triggered.connect(self.handle_default_docker_pipeline_action)
107
+ boa_docker_pipeline_action = QAction('BoaDockerPipeline', self)
108
+ boa_docker_pipeline_action.triggered.connect(self.handle_boa_docker_pipeline_action)
105
109
  pipelines_menu = self.menuBar().addMenu('Pipelines')
106
110
  pipelines_menu.addAction(default_pipeline_action)
107
111
  pipelines_menu.addAction(default_docker_pipeline_action)
112
+ pipelines_menu.addAction(boa_docker_pipeline_action)
108
113
 
109
114
  def init_visualizations_menu(self):
110
115
  slice_visualization_action = QAction('SliceVisualization', self)
@@ -134,6 +139,7 @@ class MainWindow(QMainWindow):
134
139
  self._main_panel.add_panel(self.select_slice_from_scans_task_panel(), 'selectslicefromscanstaskpanel')
135
140
  self._main_panel.add_panel(self.default_pipeline_panel(), 'defaultpipelinepanel')
136
141
  self._main_panel.add_panel(self.default_docker_pipeline_panel(), 'defaultdockerpipelinepanel')
142
+ self._main_panel.add_panel(self.boa_docker_pipeline_panel(), 'boadockerpipelinepanel')
137
143
  self._main_panel.add_panel(self.slice_visualization(), 'slicevisualization')
138
144
  self._main_panel.select_panel('defaultpipelinepanel')
139
145
  return self._main_panel
@@ -190,6 +196,11 @@ class MainWindow(QMainWindow):
190
196
  if not self._default_docker_pipeline_panel:
191
197
  self._default_docker_pipeline_panel = DefaultDockerPipelinePanel()
192
198
  return self._default_docker_pipeline_panel
199
+
200
+ def boa_docker_pipeline_panel(self):
201
+ if not self._boa_docker_pipeline_panel:
202
+ self._boa_docker_pipeline_panel = BoaDockerPipelinePanel()
203
+ return self._boa_docker_pipeline_panel
193
204
 
194
205
  def slice_visualization(self):
195
206
  if not self._slice_visualization:
@@ -230,6 +241,9 @@ class MainWindow(QMainWindow):
230
241
  def handle_default_docker_pipeline_action(self):
231
242
  self.main_panel().select_panel('defaultdockerpipelinepanel')
232
243
 
244
+ def handle_boa_docker_pipeline_action(self):
245
+ self.main_panel().select_panel('boadockerpipelinepanel')
246
+
233
247
  def handle_slice_visualization_action(self):
234
248
  self.main_panel().select_panel('slicevisualization')
235
249
 
@@ -248,6 +262,7 @@ class MainWindow(QMainWindow):
248
262
  self.select_slice_from_scans_task_panel().save_inputs_and_parameters()
249
263
  self.default_pipeline_panel().save_inputs_and_parameters()
250
264
  self.default_docker_pipeline_panel().save_inputs_and_parameters()
265
+ self.boa_docker_pipeline_panel().save_inputs_and_parameters()
251
266
  self.slice_visualization().save_inputs_and_parameters()
252
267
  return super().closeEvent(event)
253
268
 
@@ -1 +1 @@
1
- 2.0.11
1
+ 2.0.13
@@ -0,0 +1,185 @@
1
+ import os
2
+
3
+ from PySide6.QtWidgets import (
4
+ QLineEdit,
5
+ QCheckBox,
6
+ QHBoxLayout,
7
+ QVBoxLayout,
8
+ QFormLayout,
9
+ QPushButton,
10
+ QFileDialog,
11
+ QMessageBox,
12
+ )
13
+ from PySide6.QtCore import (
14
+ QThread,
15
+ Slot,
16
+ )
17
+
18
+ from mosamatic2.core.managers.logmanager import LogManager
19
+ from mosamatic2.ui.widgets.panels.pipelines.pipelinepanel import PipelinePanel
20
+ from mosamatic2.ui.settings import Settings
21
+ from mosamatic2.ui.utils import is_macos
22
+ from mosamatic2.ui.worker import Worker
23
+ from mosamatic2.core.pipelines import BoaDockerPipeline
24
+
25
+ LOG = LogManager()
26
+
27
+ PANEL_TITLE = 'BoaDockerPipeline'
28
+ PANEL_NAME = 'boadockerpipeline'
29
+
30
+
31
+ class BoaDockerPipelinePanel(PipelinePanel):
32
+ def __init__(self):
33
+ super(BoaDockerPipelinePanel, self).__init__()
34
+ self.set_title(PANEL_TITLE)
35
+ self._scans_dir_line_edit = None
36
+ self._images_dir_select_button = None
37
+ self._output_dir_line_edit = None
38
+ self._output_dir_select_button = None
39
+ self._overwrite_checkbox = None
40
+ self._form_layout = None
41
+ self._run_pipeline_button = None
42
+ self._settings = None
43
+ self._task = None
44
+ self._worker = None
45
+ self._thread = None
46
+ self.init_layout()
47
+
48
+ def scans_dir_line_edit(self):
49
+ if not self._scans_dir_line_edit:
50
+ self._scans_dir_line_edit = QLineEdit()
51
+ self._scans_dir_line_edit.setText(self.settings().get(f'{PANEL_NAME}/scans_dir'))
52
+ return self._scans_dir_line_edit
53
+
54
+ def scans_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_scans_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()
63
+ self._output_dir_line_edit.setText(self.settings().get(f'{PANEL_NAME}/output_dir'))
64
+ return self._output_dir_line_edit
65
+
66
+ def output_dir_select_button(self):
67
+ if not self._output_dir_select_button:
68
+ self._output_dir_select_button = QPushButton('Select')
69
+ self._output_dir_select_button.clicked.connect(self.handle_output_dir_select_button)
70
+ return self._output_dir_select_button
71
+
72
+ def overwrite_checkbox(self):
73
+ if not self._overwrite_checkbox:
74
+ self._overwrite_checkbox = QCheckBox('')
75
+ self._overwrite_checkbox.setChecked(self.settings().get_bool(f'{PANEL_NAME}/overwrite', True))
76
+ return self._overwrite_checkbox
77
+
78
+ def form_layout(self):
79
+ if not self._form_layout:
80
+ self._form_layout = QFormLayout()
81
+ if is_macos():
82
+ self._form_layout.setFieldGrowthPolicy(QFormLayout.ExpandingFieldsGrow)
83
+ return self._form_layout
84
+
85
+ def run_pipeline_button(self):
86
+ if not self._run_pipeline_button:
87
+ self._run_pipeline_button = QPushButton('Run pipeline')
88
+ self._run_pipeline_button.clicked.connect(self.handle_run_pipeline_button)
89
+ return self._run_pipeline_button
90
+
91
+ def settings(self):
92
+ if not self._settings:
93
+ self._settings = Settings()
94
+ return self._settings
95
+
96
+ def init_help_dialog(self):
97
+ self.help_dialog().set_text('Show some help information')
98
+
99
+ def init_layout(self):
100
+ scans_dir_layout = QHBoxLayout()
101
+ scans_dir_layout.addWidget(self.scans_dir_line_edit())
102
+ scans_dir_layout.addWidget(self.scans_dir_select_button())
103
+ output_dir_layout = QHBoxLayout()
104
+ output_dir_layout.addWidget(self.output_dir_line_edit())
105
+ output_dir_layout.addWidget(self.output_dir_select_button())
106
+ self.form_layout().addRow('Scans directory', scans_dir_layout)
107
+ self.form_layout().addRow('Output directory', output_dir_layout)
108
+ self.form_layout().addRow('Overwrite', self.overwrite_checkbox())
109
+ layout = QVBoxLayout()
110
+ layout.addLayout(self.form_layout())
111
+ layout.addWidget(self.run_pipeline_button())
112
+ self.setLayout(layout)
113
+ self.setObjectName(PANEL_NAME)
114
+
115
+ def handle_scans_dir_select_button(self):
116
+ last_directory = self.settings().get('last_directory')
117
+ directory = QFileDialog.getExistingDirectory(dir=last_directory)
118
+ if directory:
119
+ self.scans_dir_line_edit().setText(directory)
120
+ self.settings().set('last_directory', directory)
121
+
122
+ def handle_output_dir_select_button(self):
123
+ last_directory = self.settings().get('last_directory')
124
+ directory = QFileDialog.getExistingDirectory(dir=last_directory)
125
+ if directory:
126
+ self.output_dir_line_edit().setText(directory)
127
+ self.settings().set('last_directory', directory)
128
+
129
+ def handle_run_pipeline_button(self):
130
+ errors = self.check_inputs_and_parameters()
131
+ if len(errors) > 0:
132
+ error_message = 'Following errors were encountered:\n'
133
+ for error in errors:
134
+ error_message += f' - {error}\n'
135
+ QMessageBox.information(self, 'Error', error_message)
136
+ else:
137
+ LOG.info('Running pipeline...')
138
+ self.run_pipeline_button().setEnabled(False)
139
+ self.save_inputs_and_parameters()
140
+ self._task = BoaDockerPipeline(
141
+ inputs={'scans': self.scans_dir_line_edit().text()},
142
+ params=None,
143
+ output=self.output_dir_line_edit().text(),
144
+ overwrite=self.overwrite_checkbox().isChecked(),
145
+ )
146
+ self._worker = Worker(self._task)
147
+ self._thread = QThread()
148
+ self._worker.moveToThread(self._thread)
149
+ self._thread.started.connect(self._worker.run)
150
+ self._worker.progress.connect(self.handle_progress)
151
+ self._worker.status.connect(self.handle_status)
152
+ self._worker.finished.connect(self.handle_finished)
153
+ self._worker.finished.connect(self._thread.quit)
154
+ self._worker.finished.connect(self._worker.deleteLater)
155
+ self._thread.finished.connect(self._thread.deleteLater)
156
+ self._thread.start()
157
+
158
+ @Slot(int)
159
+ def handle_progress(self, progress):
160
+ LOG.info(f'Progress: {progress} / 100%')
161
+
162
+ @Slot(str)
163
+ def handle_status(self, status):
164
+ LOG.info(f'Status: {status}')
165
+
166
+ @Slot()
167
+ def handle_finished(self):
168
+ self.run_pipeline_button().setEnabled(True)
169
+
170
+ def check_inputs_and_parameters(self):
171
+ errors = []
172
+ if self.scans_dir_line_edit().text() == '':
173
+ errors.append('Empty scans directory path')
174
+ elif not os.path.isdir(self.scans_dir_line_edit().text()):
175
+ errors.append('Scans directory does not exist')
176
+ if self.output_dir_line_edit().text() == '':
177
+ errors.append('Empty output directory path')
178
+ elif os.path.isdir(self.output_dir_line_edit().text()) and not self.overwrite_checkbox().isChecked():
179
+ errors.append('Output directory exists but overwrite=False. Please remove output directory first')
180
+ return errors
181
+
182
+ def save_inputs_and_parameters(self):
183
+ self.settings().set(f'{PANEL_NAME}/scans_dir', self.scans_dir_line_edit().text())
184
+ self.settings().set(f'{PANEL_NAME}/output_dir', self.output_dir_line_edit().text())
185
+ self.settings().set(f'{PANEL_NAME}/overwrite', self.overwrite_checkbox().isChecked())
@@ -182,7 +182,6 @@ class DefaultDockerPipelinePanel(PipelinePanel):
182
182
  self.form_layout().addRow('Images directory', images_dir_layout)
183
183
  self.form_layout().addRow('Model files directory', model_files_dir_layout)
184
184
  self.form_layout().addRow('Output directory', output_dir_layout)
185
- # self.form_layout().addRow('Version', self.version_line_edit())
186
185
  self.form_layout().addRow('Overwrite', self.overwrite_checkbox())
187
186
  layout = QVBoxLayout()
188
187
  layout.addLayout(self.form_layout())
@@ -289,23 +288,10 @@ class DefaultDockerPipelinePanel(PipelinePanel):
289
288
  errors.append('Empty output directory path')
290
289
  elif os.path.isdir(self.output_dir_line_edit().text()) and not self.overwrite_checkbox().isChecked():
291
290
  errors.append('Output directory exists but overwrite=False. Please remove output directory first')
292
- # if self.version_line_edit().text() == '':
293
- # errors.append('Empty version. Should be same as current Mosamatic version')
294
- # if self.target_size_spinbox().value() != 512:
295
- # errors.append('Target size must be 512')
296
- # if self.full_scan_checkbox().isChecked():
297
- # errors.append('Full scan support is not available yet')
298
291
  return errors
299
292
 
300
293
  def save_inputs_and_parameters(self):
301
294
  self.settings().set(f'{PANEL_NAME}/images_dir', self.images_dir_line_edit().text())
302
295
  self.settings().set(f'{PANEL_NAME}/model_files_dir', self.model_files_dir_line_edit().text())
303
296
  self.settings().set(f'{PANEL_NAME}/output_dir', self.output_dir_line_edit().text())
304
- # self.settings().set(f'{PANEL_NAME}/version', self.version_line_edit().text())
305
- # self.settings().set(f'{PANEL_NAME}/target_size', self.target_size_spinbox().value())
306
- # self.settings().set(f'{PANEL_NAME}/model_type', self.model_type_combobox().currentText())
307
- # self.settings().set(f'{PANEL_NAME}/model_version', self.model_version_combobox().currentText())
308
- # self.settings().set(f'{PANEL_NAME}/fig_width', self.fig_width_spinbox().value())
309
- # self.settings().set(f'{PANEL_NAME}/fig_height', self.fig_height_spinbox().value())
310
- # self.settings().set(f'{PANEL_NAME}/full_scan', self.full_scan_checkbox().isChecked())
311
297
  self.settings().set(f'{PANEL_NAME}/overwrite', self.overwrite_checkbox().isChecked())
@@ -33,8 +33,8 @@ class Dicom2NiftiTaskPanel(TaskPanel):
33
33
  def __init__(self):
34
34
  super(Dicom2NiftiTaskPanel, self).__init__()
35
35
  self.set_title(PANEL_TITLE)
36
- self._images_dir_line_edit = None
37
- self._images_dir_select_button = None
36
+ self._scans_dir_line_edit = None
37
+ self._scans_dir_select_button = None
38
38
  self._output_dir_line_edit = None
39
39
  self._output_dir_select_button = None
40
40
  self._overwrite_checkbox = None
@@ -46,16 +46,16 @@ class Dicom2NiftiTaskPanel(TaskPanel):
46
46
  self._thread = None
47
47
  self.init_layout()
48
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
49
+ def scans_dir_line_edit(self):
50
+ if not self._scans_dir_line_edit:
51
+ self._scans_dir_line_edit = QLineEdit(self.settings().get(f'{PANEL_NAME}/scans_dir'))
52
+ return self._scans_dir_line_edit
53
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
54
+ def scans_dir_select_button(self):
55
+ if not self._scans_dir_select_button:
56
+ self._scans_dir_select_button = QPushButton('Select')
57
+ self._scans_dir_select_button.clicked.connect(self.handle_scans_dir_select_button)
58
+ return self._scans_dir_select_button
59
59
 
60
60
  def output_dir_line_edit(self):
61
61
  if not self._output_dir_line_edit:
@@ -93,13 +93,13 @@ class Dicom2NiftiTaskPanel(TaskPanel):
93
93
  return self._settings
94
94
 
95
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())
96
+ scans_dir_layout = QHBoxLayout()
97
+ scans_dir_layout.addWidget(self.scans_dir_line_edit())
98
+ scans_dir_layout.addWidget(self.scans_dir_select_button())
99
99
  output_dir_layout = QHBoxLayout()
100
100
  output_dir_layout.addWidget(self.output_dir_line_edit())
101
101
  output_dir_layout.addWidget(self.output_dir_select_button())
102
- self.form_layout().addRow('Images directory', images_dir_layout)
102
+ self.form_layout().addRow('Scans directory', scans_dir_layout)
103
103
  self.form_layout().addRow('Output directory', output_dir_layout)
104
104
  self.form_layout().addRow('Overwrite', self.overwrite_checkbox())
105
105
  layout = QVBoxLayout()
@@ -108,11 +108,11 @@ class Dicom2NiftiTaskPanel(TaskPanel):
108
108
  self.setLayout(layout)
109
109
  self.setObjectName(PANEL_NAME)
110
110
 
111
- def handle_images_dir_select_button(self):
111
+ def handle_scans_dir_select_button(self):
112
112
  last_directory = self.settings().get('last_directory')
113
113
  directory = QFileDialog.getExistingDirectory(dir=last_directory)
114
114
  if directory:
115
- self.images_dir_line_edit().setText(directory)
115
+ self.scans_dir_line_edit().setText(directory)
116
116
  self.settings().set('last_directory', directory)
117
117
 
118
118
  def handle_output_dir_select_button(self):
@@ -134,7 +134,7 @@ class Dicom2NiftiTaskPanel(TaskPanel):
134
134
  self.run_task_button().setEnabled(False)
135
135
  self.save_inputs_and_parameters()
136
136
  self._task = Dicom2NiftiTask(
137
- inputs={'images': self.images_dir_line_edit().text()},
137
+ inputs={'scans': self.scans_dir_line_edit().text()},
138
138
  params=None,
139
139
  output=self.output_dir_line_edit().text(),
140
140
  overwrite=self.overwrite_checkbox().isChecked(),
@@ -167,10 +167,10 @@ class Dicom2NiftiTaskPanel(TaskPanel):
167
167
 
168
168
  def check_inputs_and_parameters(self):
169
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')
170
+ if self.scans_dir_line_edit().text() == '':
171
+ errors.append('Empty scans directory path')
172
+ if not os.path.isdir(self.scans_dir_line_edit().text()):
173
+ errors.append('Scans directory does not exist')
174
174
  if self.output_dir_line_edit().text() == '':
175
175
  errors.append('Empty output directory path')
176
176
  if os.path.isdir(self.output_dir_line_edit().text()) and not self.overwrite_checkbox().isChecked():
@@ -178,6 +178,6 @@ class Dicom2NiftiTaskPanel(TaskPanel):
178
178
  return errors
179
179
 
180
180
  def save_inputs_and_parameters(self):
181
- self.settings().set(f'{PANEL_NAME}/images_dir', self.images_dir_line_edit().text())
181
+ self.settings().set(f'{PANEL_NAME}/scans_dir', self.scans_dir_line_edit().text())
182
182
  self.settings().set(f'{PANEL_NAME}/output_dir', self.output_dir_line_edit().text())
183
183
  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.11
3
+ Version: 2.0.13
4
4
  Summary:
5
5
  Author: Ralph Brecheisen
6
6
  Author-email: r.brecheisen@maastrichtuniversity.nl
@@ -9,6 +9,7 @@ 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
13
  Requires-Dist: flask (>=3.1.2)
13
14
  Requires-Dist: moosez
14
15
  Requires-Dist: nibabel (>=5.3.2)
@@ -1,13 +1,15 @@
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=EhGBs8AZjgZBBDFkWBNRuKd9o37Zo116DlKHHFBhoBo,1444
4
+ mosamatic2/cli.py,sha256=Fzsz1-uziNRabnBRvqyRcXFpQ7CGLF1dt4w7Js-Y1u8,1614
5
5
  mosamatic2/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
+ mosamatic2/commands/boadockerpipeline.py,sha256=-k9rQlhixfcqGUy29SsKYVXxZFri6DcnWaV6utJ6mhI,1344
6
7
  mosamatic2/commands/calculatescores.py,sha256=Lb8Q8L2yq7Tt6VBJ6_lltRuldrev_pac6fcgF-xzZyE,1984
7
8
  mosamatic2/commands/createdicomsummary.py,sha256=qbVgWGIJPBL8vTBcAxfThloQ_q15OfQy5ohMprzZL4E,1955
8
9
  mosamatic2/commands/createpngsfromsegmentations.py,sha256=uUAQJVTqOkBCfENzi21RBNYvf6_nuesx1MeR3j_-7dM,1682
10
+ mosamatic2/commands/defaultdockerpipeline.py,sha256=IxnpnIIsFH2u3aBLKgrHUb_Au72ajlIzzVe6Y0MFHJU,2025
9
11
  mosamatic2/commands/defaultpipeline.py,sha256=-kQRSXbEDimAdy_kT1qMxRlZWUoXdu3PkWf70PCIS5Y,1734
10
- mosamatic2/commands/dicom2nifti.py,sha256=4hMvglxdOid7p7P_Jc-Tudsf93JRMlYaQsEQctLq2d4,1015
12
+ mosamatic2/commands/dicom2nifti.py,sha256=uzI3-QT8_HtwXKkX5kRJzMKssM5dvJGUjZ1Z-XkwLYc,1366
11
13
  mosamatic2/commands/rescaledicomimages.py,sha256=25QdCzB5s0sRwkTb3o5zco2bIwy6LttNf7i97kGBDYQ,1280
12
14
  mosamatic2/commands/segmentmusclefatl3tensorflow.py,sha256=CdScmA_EQicaN4GY5bBUOYwfhDPqy9om2sxY3WrtmM0,1424
13
15
  mosamatic2/commands/selectslicefromscans.py,sha256=3398PM2uBcxF6wpb0-c-Itp_qxoAxBf0SE2nDDI3Ct4,1715
@@ -19,44 +21,48 @@ mosamatic2/core/data/dicomimageseries.py,sha256=OZkNi15crL8nEA-PGYsM0k9NMi2mMHRv
19
21
  mosamatic2/core/data/dixonseries.py,sha256=kq9fy65MSM2XwiScqp7b3rQ09JmpyGwbG6ldZsuPRrM,516
20
22
  mosamatic2/core/data/filedata.py,sha256=hCnpizGqOpxzIADJkDS2_NSmKVLL1u49TYjSJE5UXQo,515
21
23
  mosamatic2/core/data/multidicomimage.py,sha256=cdd0H4Dq49h7NLKBx51_h_HZVnH7-reu48PY8m6tXwU,1034
22
- mosamatic2/core/data/multinumpyimage.py,sha256=MU5_ec00vx9_JhkibgkcgyGFfaj69STy85ifa8MNsSc,753
23
- mosamatic2/core/data/numpyimage.py,sha256=ZbJ9JRAVOgvXzTZ6kscEuGZJqKT-MPdt42IAlmh3iXo,359
24
+ mosamatic2/core/data/multiniftiimage.py,sha256=zkHRPzKE-fyP9MtlheJyo_OoqpFXmYMxwguZXP-9bdw,753
25
+ mosamatic2/core/data/multinumpyimage.py,sha256=bISFxDHJ2aFuutCLpwQoiuPkMfVQf_Uc0WslZ4ruJ3o,753
26
+ mosamatic2/core/data/niftiimage.py,sha256=s4WGADwnzlSgHx80isM58J6cHdhKXF2e3zuGvJzew-M,347
27
+ mosamatic2/core/data/numpyimage.py,sha256=bnG6WVGSRxNdzIlb2DNj5u6Gv4BAYscIj2BuyjkDjEc,359
24
28
  mosamatic2/core/managers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
29
  mosamatic2/core/managers/logmanager.py,sha256=NEaXvhl0aILjBbK710GaWanVuuNvB51HpHhE5rgYvng,1391
26
30
  mosamatic2/core/managers/logmanagerlistener.py,sha256=Gaig07yjBnyQq9I8sN85olTEeDCDyCFQnEJdwzvmgvc,99
27
- mosamatic2/core/pipelines/__init__.py,sha256=2RjHG0xLO-_QK-yw0RHrJe85B-SZ4oAKUJWrDzrLdGI,190
31
+ mosamatic2/core/pipelines/__init__.py,sha256=YPlyO5L_DMrTyO2-2TBq_Bdg-bbMHQiicXJafn66Dg8,283
32
+ mosamatic2/core/pipelines/boadockerpipeline/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
+ mosamatic2/core/pipelines/boadockerpipeline/boadockerpipeline.py,sha256=KFZk_L_0KaTdUqHjqGW8MysbCIOKlUKWP8S-T9xyvis,2939
28
34
  mosamatic2/core/pipelines/defaultdockerpipeline/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
29
- mosamatic2/core/pipelines/defaultdockerpipeline/defaultdockerpipeline.py,sha256=gb-rez0Y3jY6_c7llfwN2IDnl9l5Fz3XyvScLmWA7Y4,1490
35
+ mosamatic2/core/pipelines/defaultdockerpipeline/defaultdockerpipeline.py,sha256=m_f9c7MmvSRqERF6n-nLGxa6xP13xtoSihW53d387zU,1315
30
36
  mosamatic2/core/pipelines/defaultpipeline/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
31
37
  mosamatic2/core/pipelines/defaultpipeline/defaultpipeline.py,sha256=Bme0r_shnrllWYCYDNc6cLM2fQC2yD8RJKpRdoh_6Uc,3077
32
38
  mosamatic2/core/pipelines/pipeline.py,sha256=mRxKXLKwgKDpc8R9mCI6gDKGJ2lKVxRQ__Sf0Mfn_Qc,384
33
39
  mosamatic2/core/singleton.py,sha256=FV0k_LlOCmFhlWN6gf1c2x7YXWyd8-7DsIMvOKrI6NY,224
34
40
  mosamatic2/core/tasks/__init__.py,sha256=w03AyCk2BQ6gGPBEKhtad6lt9WuwHC-nMztv7wQNwb4,759
35
41
  mosamatic2/core/tasks/calculatescorestask/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
- mosamatic2/core/tasks/calculatescorestask/calculatescorestask.py,sha256=jEbogrEnEtMbmfQ8KOGSUdGMhdeX69Bv01-82faRIlY,6617
42
+ mosamatic2/core/tasks/calculatescorestask/calculatescorestask.py,sha256=cwGVedJR_BGSYzXq6ouTgCbSC6s2VtyD8FzRC-QBXUI,6617
37
43
  mosamatic2/core/tasks/createdicomsummarytask/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
44
  mosamatic2/core/tasks/createdicomsummarytask/createdicomsummarytask.py,sha256=kcdwIBnoAXexok2j6_tF_s6gwvn2DvjLwe_VhdODpbM,2957
39
45
  mosamatic2/core/tasks/createpngsfromsegmentationstask/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
40
46
  mosamatic2/core/tasks/createpngsfromsegmentationstask/createpngsfromsegmentationstask.py,sha256=1UpOsp1CH668BQ0g4tALou_tFgisC306VcvqOKSDuTo,1884
41
47
  mosamatic2/core/tasks/dicom2niftitask/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
42
- mosamatic2/core/tasks/dicom2niftitask/dicom2niftitask.py,sha256=9VqDDCShUG09Qhppia-5X-rkVbUzI4VF8rBVia19Tvs,762
48
+ mosamatic2/core/tasks/dicom2niftitask/dicom2niftitask.py,sha256=jvkgC5rkSC0kAy_OXM10RsjAUYi6A76dYjCXQmpycFY,1436
43
49
  mosamatic2/core/tasks/rescaledicomimagestask/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
44
50
  mosamatic2/core/tasks/rescaledicomimagestask/rescaledicomimagestask.py,sha256=vGSpMJoXFtE-IHGxTEO9DMkerMJcfG5r9tXgtvkxm6Y,3053
45
51
  mosamatic2/core/tasks/segmentmusclefatl3tensorflowtask/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
46
52
  mosamatic2/core/tasks/segmentmusclefatl3tensorflowtask/paramloader.py,sha256=VxTCOYK_1VRAG83P-ulm0LPvqXI-0iT5BCr0Rdr7MWg,900
47
- mosamatic2/core/tasks/segmentmusclefatl3tensorflowtask/segmentmusclefatl3tensorflowtask.py,sha256=E3GHzGtl-v_qIdLjSy3cbDnf8vfWK6Bax3RAZcKCqXg,5149
53
+ mosamatic2/core/tasks/segmentmusclefatl3tensorflowtask/segmentmusclefatl3tensorflowtask.py,sha256=IEE-31eLmq7Y47YL5pT3QUdf9ET8Ju-Z3OxniraZUbA,5245
48
54
  mosamatic2/core/tasks/selectslicefromscanstask/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
49
- mosamatic2/core/tasks/selectslicefromscanstask/selectslicefromscanstask.py,sha256=kENwpV4Omlg-EUPTQYaSqDbkNhIQ8vZeA3Tlz15eXBw,7251
55
+ mosamatic2/core/tasks/selectslicefromscanstask/selectslicefromscanstask.py,sha256=EIEHhWoGL30rcz8qckFl465rU40P-pIkvhMOfSud7Yw,7253
50
56
  mosamatic2/core/tasks/task.py,sha256=APPnid6dpSGkPuDqU1vm2RIMR5vkpvbP1CPHUMjympg,1691
51
- mosamatic2/core/utils.py,sha256=iib_o_dD4hnqGIgOxLOfvMFOqLZOpt0iT_8Oarkmdjs,11723
57
+ mosamatic2/core/utils.py,sha256=y8ujz-sX5nMH2eqvCyzXK2AqYCVVppvJFmGi0UgFXTk,12170
52
58
  mosamatic2/server.py,sha256=-cZ9BPsZUXoINKqwhCHN8c59mlvzzDXzTVxsYt9au70,4644
53
59
  mosamatic2/ui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
54
- mosamatic2/ui/mainwindow.py,sha256=H1X1pLJjqd2DhxJY0ZU6QkktX28zl0pmtFflmOxrGZA,14048
60
+ mosamatic2/ui/mainwindow.py,sha256=XpVqNpOvfULXVaXYHjey4RMhgh4zvvVWfxKFIjTXwO4,14925
55
61
  mosamatic2/ui/resources/icons/mosamatic2.icns,sha256=OfhC-diJTIgaNMOezxKKilGsY7mRkaGdU5dGr0MOjIA,2994125
56
62
  mosamatic2/ui/resources/icons/mosamatic2.ico,sha256=ySD3RYluHK3pgS0Eas7eKrVk_AskdLQ4qs_IT-wNhq4,12229
57
63
  mosamatic2/ui/resources/icons/spinner.gif,sha256=rvaac6GUZauHSPFSOLWr0RmLfjmtZih2Q8knQ2WP3Po,16240
58
64
  mosamatic2/ui/resources/images/body-composition.jpg,sha256=KD-BudbXwThB4lJOZZN-ad5-TZRaaZ5cKTH0Ar1TOZs,21227
59
- mosamatic2/ui/resources/VERSION,sha256=y0GqH9MTkPlMyl8fiOr-IbS7ffiCOAoUIM8ee5UYv7s,9
65
+ mosamatic2/ui/resources/VERSION,sha256=haUTerigaCYg0i4VyXT58-MrbAbBF_QkcCNhH9O8PxU,9
60
66
  mosamatic2/ui/settings.py,sha256=YEVHYJIfNsqMO3v1pjzgh7Pih9GGoUX7S9s8S-sBNUk,2121
61
67
  mosamatic2/ui/utils.py,sha256=6bbPIrh4RJ_yhQKNZrgPbL4XeUEogjIjbk_e5c3QS5g,853
62
68
  mosamatic2/ui/widgets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -68,7 +74,8 @@ mosamatic2/ui/widgets/panels/defaultpanel.py,sha256=Ry32Xv6ibxm6NdZ7eBOCcisWNcmn
68
74
  mosamatic2/ui/widgets/panels/logpanel.py,sha256=ogswJ6_ryb6u7JeVnOsh2Ez8KWg6jtCFZwij8s87xO4,1861
69
75
  mosamatic2/ui/widgets/panels/mainpanel.py,sha256=KqI8dA7GpLFd2unqVRTBkNxdnh6AWGpVPwQuaEg8PmI,2431
70
76
  mosamatic2/ui/widgets/panels/pipelines/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
71
- mosamatic2/ui/widgets/panels/pipelines/defaultdockerpipelinepanel.py,sha256=SRS6gBhnymgRM6TmaqJgzHzHfffkWucMCjsuzDgJdBg,14415
77
+ mosamatic2/ui/widgets/panels/pipelines/boadockerpipelinepanel.py,sha256=bsyyt-42Qho6D4rpSjo9sBJBM9ISOChX-N8QWc3j2s0,7711
78
+ mosamatic2/ui/widgets/panels/pipelines/defaultdockerpipelinepanel.py,sha256=smEymbmYQ1wy0lgkhjGAGhXQedIhE8wjiX2TqYF6VB8,13284
72
79
  mosamatic2/ui/widgets/panels/pipelines/defaultpipelinepanel.py,sha256=qkfI4BnLIXqE_YvSQj4sO_FjnK0eVdIMqAZ8sktgI-8,13727
73
80
  mosamatic2/ui/widgets/panels/pipelines/pipelinepanel.py,sha256=SlkKme8Wv2Bvp2Alen98mFjv3F5eZCwJylj294gd5uU,178
74
81
  mosamatic2/ui/widgets/panels/stackedpanel.py,sha256=dK1YWuHUzxRhVb5gP0Lu9rAiW4XagjcHmGF__5Lpufk,657
@@ -76,7 +83,7 @@ mosamatic2/ui/widgets/panels/tasks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQe
76
83
  mosamatic2/ui/widgets/panels/tasks/calculatescorestaskpanel.py,sha256=NmPLQizj4x9jgf9UA7VZSjARNHYJB_jrfB0kvaVncdw,9387
77
84
  mosamatic2/ui/widgets/panels/tasks/createdicomsummarytaskpanel.py,sha256=cRCaEmjjZP6RwEhezj2Axxuv8uAGe7ZzHoU67asoZ5s,7530
78
85
  mosamatic2/ui/widgets/panels/tasks/createpngsfromsegmentationstaskpanel.py,sha256=JFnmYjPemRtXPXV2fk2cjB45fseN5BZ8gI_T1zVLGV8,7879
79
- mosamatic2/ui/widgets/panels/tasks/dicom2niftitaskpanel.py,sha256=gIv5xo0z2EEfFzHI4Q6H87maf-nPIeC8yIxLL5iWuCw,7480
86
+ mosamatic2/ui/widgets/panels/tasks/dicom2niftitaskpanel.py,sha256=6gtaMCZMAbLGv0pOHd4fHBFOluIptFfGOA-vGvrYKGI,7450
80
87
  mosamatic2/ui/widgets/panels/tasks/rescaledicomimagestaskpanel.py,sha256=ds7JxynpMeNvqfHKtg1LQR23rb3_Y7xoDLbZ2wl-TMw,7597
81
88
  mosamatic2/ui/widgets/panels/tasks/segmentmusclefatl3tensorflowtaskpanel.py,sha256=QCEZs9lqaE-XAJuyyrfZVnFkNRyjMw6Cfa-6qP9WaV8,9630
82
89
  mosamatic2/ui/widgets/panels/tasks/selectslicefromscanstaskpanel.py,sha256=meKltgxPReZ9HioSop6jW_2CFm18URBy3LX11U8tbtc,8059
@@ -89,7 +96,7 @@ mosamatic2/ui/widgets/panels/visualizations/slicevisualization/slicevisualizatio
89
96
  mosamatic2/ui/widgets/panels/visualizations/visualization.py,sha256=JvqTJi7cCGYK1-wrN2oURdCOBoPS2clVUyYglhkoVJg,178
90
97
  mosamatic2/ui/widgets/splashscreen.py,sha256=MS-OczOWfwwEQNQd-JWe9_Mh57css0cSQgbu973rwQo,4056
91
98
  mosamatic2/ui/worker.py,sha256=v7e3gq7MUudgpB1BJW-P7j5wurzu6-HG5m7I6WHgJp0,699
92
- mosamatic2-2.0.11.dist-info/entry_points.txt,sha256=MCUpKkgbej1clgp8EqlLQGs0BIKwGPcBPiVWLfGz9Gw,126
93
- mosamatic2-2.0.11.dist-info/METADATA,sha256=PB1v5wdjawm3d8_s3bvssSzlrxfPNLSGLMD-U8X9NrI,1490
94
- mosamatic2-2.0.11.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
95
- mosamatic2-2.0.11.dist-info/RECORD,,
99
+ mosamatic2-2.0.13.dist-info/entry_points.txt,sha256=MCUpKkgbej1clgp8EqlLQGs0BIKwGPcBPiVWLfGz9Gw,126
100
+ mosamatic2-2.0.13.dist-info/METADATA,sha256=XbbE0-CmpimvfTRszW3lSFBavSLHjMhcmSuGZ-R6WaU,1512
101
+ mosamatic2-2.0.13.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
102
+ mosamatic2-2.0.13.dist-info/RECORD,,