biomedisa 24.5.23__tar.gz → 24.8.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {biomedisa-24.5.23 → biomedisa-24.8.1}/PKG-INFO +18 -12
- {biomedisa-24.5.23 → biomedisa-24.8.1}/README.md +17 -11
- {biomedisa-24.5.23 → biomedisa-24.8.1}/pyproject.toml +1 -1
- {biomedisa-24.5.23 → biomedisa-24.8.1}/src/biomedisa/deeplearning.py +38 -33
- {biomedisa-24.5.23 → biomedisa-24.8.1}/src/biomedisa/features/DataGenerator.py +1 -1
- {biomedisa-24.5.23 → biomedisa-24.8.1}/src/biomedisa/features/active_contour.py +3 -10
- {biomedisa-24.5.23 → biomedisa-24.8.1}/src/biomedisa/features/biomedisa_helper.py +37 -27
- {biomedisa-24.5.23 → biomedisa-24.8.1}/src/biomedisa/features/create_slices.py +4 -3
- {biomedisa-24.5.23 → biomedisa-24.8.1}/src/biomedisa/features/crop_helper.py +2 -1
- {biomedisa-24.5.23 → biomedisa-24.8.1}/src/biomedisa/features/keras_helper.py +290 -115
- {biomedisa-24.5.23 → biomedisa-24.8.1}/src/biomedisa/features/remove_outlier.py +3 -9
- {biomedisa-24.5.23 → biomedisa-24.8.1}/src/biomedisa/interpolation.py +9 -15
- {biomedisa-24.5.23 → biomedisa-24.8.1}/src/biomedisa/mesh.py +12 -11
- {biomedisa-24.5.23 → biomedisa-24.8.1}/src/biomedisa.egg-info/PKG-INFO +18 -12
- {biomedisa-24.5.23 → biomedisa-24.8.1}/LICENSE +0 -0
- {biomedisa-24.5.23 → biomedisa-24.8.1}/setup.cfg +0 -0
- {biomedisa-24.5.23 → biomedisa-24.8.1}/src/biomedisa/__init__.py +0 -0
- {biomedisa-24.5.23 → biomedisa-24.8.1}/src/biomedisa/__main__.py +0 -0
- {biomedisa-24.5.23 → biomedisa-24.8.1}/src/biomedisa/features/DataGeneratorCrop.py +0 -0
- {biomedisa-24.5.23 → biomedisa-24.8.1}/src/biomedisa/features/PredictDataGenerator.py +0 -0
- {biomedisa-24.5.23 → biomedisa-24.8.1}/src/biomedisa/features/PredictDataGeneratorCrop.py +0 -0
- {biomedisa-24.5.23 → biomedisa-24.8.1}/src/biomedisa/features/__init__.py +0 -0
- {biomedisa-24.5.23 → biomedisa-24.8.1}/src/biomedisa/features/amira_to_np/__init__.py +0 -0
- {biomedisa-24.5.23 → biomedisa-24.8.1}/src/biomedisa/features/amira_to_np/amira_data_stream.py +0 -0
- {biomedisa-24.5.23 → biomedisa-24.8.1}/src/biomedisa/features/amira_to_np/amira_grammar.py +0 -0
- {biomedisa-24.5.23 → biomedisa-24.8.1}/src/biomedisa/features/amira_to_np/amira_header.py +0 -0
- {biomedisa-24.5.23 → biomedisa-24.8.1}/src/biomedisa/features/amira_to_np/amira_helper.py +0 -0
- {biomedisa-24.5.23 → biomedisa-24.8.1}/src/biomedisa/features/assd.py +0 -0
- {biomedisa-24.5.23 → biomedisa-24.8.1}/src/biomedisa/features/curvop_numba.py +0 -0
- {biomedisa-24.5.23 → biomedisa-24.8.1}/src/biomedisa/features/django_env.py +0 -0
- {biomedisa-24.5.23 → biomedisa-24.8.1}/src/biomedisa/features/nc_reader.py +0 -0
- {biomedisa-24.5.23 → biomedisa-24.8.1}/src/biomedisa/features/pid.py +0 -0
- {biomedisa-24.5.23 → biomedisa-24.8.1}/src/biomedisa/features/process_image.py +0 -0
- {biomedisa-24.5.23 → biomedisa-24.8.1}/src/biomedisa/features/pycuda_test.py +0 -0
- {biomedisa-24.5.23 → biomedisa-24.8.1}/src/biomedisa/features/random_walk/__init__.py +0 -0
- {biomedisa-24.5.23 → biomedisa-24.8.1}/src/biomedisa/features/random_walk/gpu_kernels.py +0 -0
- {biomedisa-24.5.23 → biomedisa-24.8.1}/src/biomedisa/features/random_walk/pycuda_large.py +0 -0
- {biomedisa-24.5.23 → biomedisa-24.8.1}/src/biomedisa/features/random_walk/pycuda_large_allx.py +0 -0
- {biomedisa-24.5.23 → biomedisa-24.8.1}/src/biomedisa/features/random_walk/pycuda_small.py +0 -0
- {biomedisa-24.5.23 → biomedisa-24.8.1}/src/biomedisa/features/random_walk/pycuda_small_allx.py +0 -0
- {biomedisa-24.5.23 → biomedisa-24.8.1}/src/biomedisa/features/random_walk/pyopencl_large.py +0 -0
- {biomedisa-24.5.23 → biomedisa-24.8.1}/src/biomedisa/features/random_walk/pyopencl_small.py +0 -0
- {biomedisa-24.5.23 → biomedisa-24.8.1}/src/biomedisa/features/random_walk/rw_large.py +0 -0
- {biomedisa-24.5.23 → biomedisa-24.8.1}/src/biomedisa/features/random_walk/rw_small.py +0 -0
- {biomedisa-24.5.23 → biomedisa-24.8.1}/src/biomedisa/features/split_volume.py +0 -0
- {biomedisa-24.5.23 → biomedisa-24.8.1}/src/biomedisa.egg-info/SOURCES.txt +0 -0
- {biomedisa-24.5.23 → biomedisa-24.8.1}/src/biomedisa.egg-info/dependency_links.txt +0 -0
- {biomedisa-24.5.23 → biomedisa-24.8.1}/src/biomedisa.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: biomedisa
|
3
|
-
Version: 24.
|
3
|
+
Version: 24.8.1
|
4
4
|
Summary: Segmentation of 3D volumetric image data
|
5
5
|
Author: Philipp Lösel
|
6
6
|
Author-email: philipp.loesel@anu.edu.au
|
@@ -33,17 +33,20 @@ License-File: LICENSE
|
|
33
33
|
- [License](#license)
|
34
34
|
|
35
35
|
## Overview
|
36
|
-
Biomedisa (https://biomedisa.info) is a free and easy-to-use open-source application for segmenting large volumetric images
|
36
|
+
Biomedisa (https://biomedisa.info) is a free and easy-to-use open-source application for segmenting large 3D volumetric images such as CT and MRI scans, developed at [The Australian National University CTLab](https://ctlab.anu.edu.au/). Biomedisa's smart interpolation of sparsely pre-segmented slices enables accurate semi-automated segmentation by considering the complete underlying image data. Additionally, Biomedisa enables deep learning for fully automated segmentation across similar samples and structures. It is compatible with segmentation tools like Amira/Avizo, ImageJ/Fiji and 3D Slicer. If you are using Biomedisa or the data for your research please cite: Lösel, P.D. et al. [Introducing Biomedisa as an open-source online platform for biomedical image segmentation.](https://www.nature.com/articles/s41467-020-19303-w) *Nat. Commun.* **11**, 5577 (2020).
|
37
37
|
|
38
38
|
## Hardware Requirements
|
39
|
-
+ One or more NVIDIA GPUs with compute capability 3.0 or higher
|
39
|
+
+ One or more NVIDIA GPUs with compute capability 3.0 or higher.
|
40
40
|
|
41
41
|
## Installation (command-line based)
|
42
|
-
+ [Ubuntu 22.04 +
|
43
|
-
+ [Ubuntu 22.04 +
|
44
|
-
+ [Windows 10 +
|
45
|
-
+ [Windows
|
46
|
-
|
42
|
+
+ [Ubuntu 22.04 + Smart Interpolation](https://github.com/biomedisa/biomedisa/blob/master/README/ubuntu2204_interpolation_cli.md)
|
43
|
+
+ [Ubuntu 22.04 + Smart Interpolation + Deep Learning](https://github.com/biomedisa/biomedisa/blob/master/README/ubuntu2204_cuda11.8_gpu_cli.md)
|
44
|
+
+ [Windows 10 + Smart Interpolation + Deep Learning](https://github.com/biomedisa/biomedisa/blob/master/README/windows10_cuda_gpu_cli.md)
|
45
|
+
+ [Windows (WSL) + Smart Interpolation + Deep Learning](https://github.com/biomedisa/biomedisa/blob/master/README/windows_wsl.md)
|
46
|
+
|
47
|
+
## Installation (3D Slicer extension)
|
48
|
+
+ [Ubuntu 22.04 + Smart Interpolation + Deep Learning](https://github.com/biomedisa/biomedisa/blob/master/README/ubuntu2204_cuda11.8_gpu_slicer.md)
|
49
|
+
+ [Windows 10 + Smart Interpolation](https://github.com/biomedisa/biomedisa/blob/master/README/windows10_cuda_gpu_slicer.md)
|
47
50
|
|
48
51
|
## Installation (browser based)
|
49
52
|
+ [Ubuntu 22.04](https://github.com/biomedisa/biomedisa/blob/master/README/ubuntu2204_cuda11.8.md)
|
@@ -52,6 +55,10 @@ Biomedisa (https://biomedisa.info) is a free and easy-to-use open-source applica
|
|
52
55
|
+ Download test data from our [gallery](https://biomedisa.info/gallery/)
|
53
56
|
|
54
57
|
## Revisions
|
58
|
+
24.7.1
|
59
|
+
+ 3D Slicer extension
|
60
|
+
+ Prediction of large data block by block
|
61
|
+
|
55
62
|
24.5.22
|
56
63
|
+ Pip is the preferred installation method
|
57
64
|
+ Commands, module names and imports have been changed to conform to the Pip standard
|
@@ -131,15 +138,14 @@ deep_learning(img_data, label_data, train=True, batch_size=12,
|
|
131
138
|
```
|
132
139
|
|
133
140
|
#### Command-line based (training)
|
134
|
-
Start training with a batch size of 12:
|
135
141
|
```
|
136
|
-
python -m biomedisa.deeplearning C:\Users\%USERNAME%\Downloads\training_heart C:\Users\%USERNAME%\Downloads\training_heart_labels -t
|
142
|
+
python -m biomedisa.deeplearning C:\Users\%USERNAME%\Downloads\training_heart C:\Users\%USERNAME%\Downloads\training_heart_labels -t
|
137
143
|
```
|
138
144
|
Monitor training progress using validation data:
|
139
145
|
```
|
140
146
|
python -m biomedisa.deeplearning C:\Users\%USERNAME%\Downloads\training_heart C:\Users\%USERNAME%\Downloads\training_heart_labels -t -vi=C:\Users\%USERNAME%\Downloads\val_img -vl=C:\Users\%USERNAME%\Downloads\val_labels
|
141
147
|
```
|
142
|
-
If running into ResourceExhaustedError due to out of memory (OOM), try to use a smaller batch size.
|
148
|
+
If running into ResourceExhaustedError due to out of memory (OOM), try to use a smaller batch size (e.g. -bs=12).
|
143
149
|
|
144
150
|
#### Python example (prediction)
|
145
151
|
```python
|
@@ -175,7 +181,7 @@ from biomedisa.mesh import get_voxel_spacing, save_mesh
|
|
175
181
|
data, header, extension = load_data('final.Head5.am', return_extension=True)
|
176
182
|
|
177
183
|
# get voxel spacing
|
178
|
-
x_res, y_res, z_res = get_voxel_spacing(header,
|
184
|
+
x_res, y_res, z_res = get_voxel_spacing(header, extension)
|
179
185
|
print(f'Voxel spacing: x_spacing, y_spacing, z_spacing = {x_res}, {y_res}, {z_res}')
|
180
186
|
|
181
187
|
# save stl file
|
@@ -17,17 +17,20 @@
|
|
17
17
|
- [License](#license)
|
18
18
|
|
19
19
|
## Overview
|
20
|
-
Biomedisa (https://biomedisa.info) is a free and easy-to-use open-source application for segmenting large volumetric images
|
20
|
+
Biomedisa (https://biomedisa.info) is a free and easy-to-use open-source application for segmenting large 3D volumetric images such as CT and MRI scans, developed at [The Australian National University CTLab](https://ctlab.anu.edu.au/). Biomedisa's smart interpolation of sparsely pre-segmented slices enables accurate semi-automated segmentation by considering the complete underlying image data. Additionally, Biomedisa enables deep learning for fully automated segmentation across similar samples and structures. It is compatible with segmentation tools like Amira/Avizo, ImageJ/Fiji and 3D Slicer. If you are using Biomedisa or the data for your research please cite: Lösel, P.D. et al. [Introducing Biomedisa as an open-source online platform for biomedical image segmentation.](https://www.nature.com/articles/s41467-020-19303-w) *Nat. Commun.* **11**, 5577 (2020).
|
21
21
|
|
22
22
|
## Hardware Requirements
|
23
|
-
+ One or more NVIDIA GPUs with compute capability 3.0 or higher
|
23
|
+
+ One or more NVIDIA GPUs with compute capability 3.0 or higher.
|
24
24
|
|
25
25
|
## Installation (command-line based)
|
26
|
-
+ [Ubuntu 22.04 +
|
27
|
-
+ [Ubuntu 22.04 +
|
28
|
-
+ [Windows 10 +
|
29
|
-
+ [Windows
|
30
|
-
|
26
|
+
+ [Ubuntu 22.04 + Smart Interpolation](https://github.com/biomedisa/biomedisa/blob/master/README/ubuntu2204_interpolation_cli.md)
|
27
|
+
+ [Ubuntu 22.04 + Smart Interpolation + Deep Learning](https://github.com/biomedisa/biomedisa/blob/master/README/ubuntu2204_cuda11.8_gpu_cli.md)
|
28
|
+
+ [Windows 10 + Smart Interpolation + Deep Learning](https://github.com/biomedisa/biomedisa/blob/master/README/windows10_cuda_gpu_cli.md)
|
29
|
+
+ [Windows (WSL) + Smart Interpolation + Deep Learning](https://github.com/biomedisa/biomedisa/blob/master/README/windows_wsl.md)
|
30
|
+
|
31
|
+
## Installation (3D Slicer extension)
|
32
|
+
+ [Ubuntu 22.04 + Smart Interpolation + Deep Learning](https://github.com/biomedisa/biomedisa/blob/master/README/ubuntu2204_cuda11.8_gpu_slicer.md)
|
33
|
+
+ [Windows 10 + Smart Interpolation](https://github.com/biomedisa/biomedisa/blob/master/README/windows10_cuda_gpu_slicer.md)
|
31
34
|
|
32
35
|
## Installation (browser based)
|
33
36
|
+ [Ubuntu 22.04](https://github.com/biomedisa/biomedisa/blob/master/README/ubuntu2204_cuda11.8.md)
|
@@ -36,6 +39,10 @@ Biomedisa (https://biomedisa.info) is a free and easy-to-use open-source applica
|
|
36
39
|
+ Download test data from our [gallery](https://biomedisa.info/gallery/)
|
37
40
|
|
38
41
|
## Revisions
|
42
|
+
24.7.1
|
43
|
+
+ 3D Slicer extension
|
44
|
+
+ Prediction of large data block by block
|
45
|
+
|
39
46
|
24.5.22
|
40
47
|
+ Pip is the preferred installation method
|
41
48
|
+ Commands, module names and imports have been changed to conform to the Pip standard
|
@@ -115,15 +122,14 @@ deep_learning(img_data, label_data, train=True, batch_size=12,
|
|
115
122
|
```
|
116
123
|
|
117
124
|
#### Command-line based (training)
|
118
|
-
Start training with a batch size of 12:
|
119
125
|
```
|
120
|
-
python -m biomedisa.deeplearning C:\Users\%USERNAME%\Downloads\training_heart C:\Users\%USERNAME%\Downloads\training_heart_labels -t
|
126
|
+
python -m biomedisa.deeplearning C:\Users\%USERNAME%\Downloads\training_heart C:\Users\%USERNAME%\Downloads\training_heart_labels -t
|
121
127
|
```
|
122
128
|
Monitor training progress using validation data:
|
123
129
|
```
|
124
130
|
python -m biomedisa.deeplearning C:\Users\%USERNAME%\Downloads\training_heart C:\Users\%USERNAME%\Downloads\training_heart_labels -t -vi=C:\Users\%USERNAME%\Downloads\val_img -vl=C:\Users\%USERNAME%\Downloads\val_labels
|
125
131
|
```
|
126
|
-
If running into ResourceExhaustedError due to out of memory (OOM), try to use a smaller batch size.
|
132
|
+
If running into ResourceExhaustedError due to out of memory (OOM), try to use a smaller batch size (e.g. -bs=12).
|
127
133
|
|
128
134
|
#### Python example (prediction)
|
129
135
|
```python
|
@@ -159,7 +165,7 @@ from biomedisa.mesh import get_voxel_spacing, save_mesh
|
|
159
165
|
data, header, extension = load_data('final.Head5.am', return_extension=True)
|
160
166
|
|
161
167
|
# get voxel spacing
|
162
|
-
x_res, y_res, z_res = get_voxel_spacing(header,
|
168
|
+
x_res, y_res, z_res = get_voxel_spacing(header, extension)
|
163
169
|
print(f'Voxel spacing: x_spacing, y_spacing, z_spacing = {x_res}, {y_res}, {z_res}')
|
164
170
|
|
165
171
|
# save stl file
|
@@ -65,11 +65,11 @@ def deep_learning(img_data, label_data=None, val_img_data=None, val_label_data=N
|
|
65
65
|
path_to_images=None, path_to_labels=None, val_images=None, val_labels=None,
|
66
66
|
path_to_model=None, predict=False, train=False, header_file=None,
|
67
67
|
balance=False, crop_data=False, flip_x=False, flip_y=False, flip_z=False,
|
68
|
-
swapaxes=False, train_dice=False, val_dice=True,
|
68
|
+
swapaxes=False, train_dice=False, val_dice=True, compression=True, ignore='none', only='all',
|
69
69
|
network_filters='32-64-128-256-512', resnet=False, debug_cropping=False,
|
70
|
-
save_cropped=False, epochs=100,
|
70
|
+
save_cropped=False, epochs=100, normalization=True, rotate=0.0, validation_split=0.0,
|
71
71
|
learning_rate=0.01, stride_size=32, validation_stride_size=32, validation_freq=1,
|
72
|
-
batch_size=None, x_scale=256, y_scale=256, z_scale=256,
|
72
|
+
batch_size=None, x_scale=256, y_scale=256, z_scale=256, scaling=True, early_stopping=0,
|
73
73
|
pretrained_model=None, fine_tune=False, workers=1, cropping_epochs=50,
|
74
74
|
x_range=None, y_range=None, z_range=None, header=None, extension='.tif',
|
75
75
|
img_header=None, img_extension='.tif', average_dice=False, django_env=False,
|
@@ -91,17 +91,13 @@ def deep_learning(img_data, label_data=None, val_img_data=None, val_label_data=N
|
|
91
91
|
for arg in key_copy:
|
92
92
|
bm.__dict__[arg] = locals()[arg]
|
93
93
|
|
94
|
-
# compression
|
95
|
-
if bm.no_compression:
|
96
|
-
bm.compression = False
|
97
|
-
else:
|
98
|
-
bm.compression = True
|
99
|
-
|
100
94
|
# normalization
|
101
|
-
if bm.
|
95
|
+
bm.normalize = 1 if bm.normalization else 0
|
96
|
+
|
97
|
+
# use patch normalization instead of normalizing the entire volume
|
98
|
+
if not bm.scaling:
|
102
99
|
bm.normalize = 0
|
103
|
-
|
104
|
-
bm.normalize = 1
|
100
|
+
bm.patch_normalization = True
|
105
101
|
|
106
102
|
# django environment
|
107
103
|
if bm.django_env:
|
@@ -217,14 +213,19 @@ def deep_learning(img_data, label_data=None, val_img_data=None, val_label_data=N
|
|
217
213
|
hf = h5py.File(bm.path_to_model, 'r')
|
218
214
|
meta = hf.get('meta')
|
219
215
|
configuration = meta.get('configuration')
|
220
|
-
channels, bm.x_scale, bm.y_scale, bm.z_scale, normalize, mu, sig = np.array(configuration)[:]
|
221
|
-
channels, bm.x_scale, bm.y_scale, bm.z_scale, normalize, mu, sig = int(channels), int(bm.x_scale), \
|
222
|
-
int(bm.y_scale), int(bm.z_scale), int(normalize), float(mu), float(sig)
|
223
|
-
if '
|
224
|
-
normalization_parameters = np.array(meta
|
216
|
+
channels, bm.x_scale, bm.y_scale, bm.z_scale, bm.normalize, mu, sig = np.array(configuration)[:]
|
217
|
+
channels, bm.x_scale, bm.y_scale, bm.z_scale, bm.normalize, mu, sig = int(channels), int(bm.x_scale), \
|
218
|
+
int(bm.y_scale), int(bm.z_scale), int(bm.normalize), float(mu), float(sig)
|
219
|
+
if 'normalization' in meta:
|
220
|
+
normalization_parameters = np.array(meta['normalization'], dtype=float)
|
225
221
|
else:
|
226
222
|
normalization_parameters = np.array([[mu],[sig]])
|
227
|
-
allLabels = np.array(meta.get('labels'))
|
223
|
+
bm.allLabels = np.array(meta.get('labels'))
|
224
|
+
if 'patch_normalization' in meta:
|
225
|
+
bm.patch_normalization = bool(meta['patch_normalization'][()])
|
226
|
+
if 'scaling' in meta:
|
227
|
+
bm.scaling = bool(meta['scaling'][()])
|
228
|
+
|
228
229
|
# check if amira header is available in the network
|
229
230
|
if header is None and meta.get('header') is not None:
|
230
231
|
header = [np.array(meta.get('header'))]
|
@@ -290,16 +291,11 @@ def deep_learning(img_data, label_data=None, val_img_data=None, val_label_data=N
|
|
290
291
|
region_of_interest, cropped_volume = ch.crop_data(bm.path_to_image, bm.path_to_model, bm.path_to_cropped_image,
|
291
292
|
bm.batch_size, bm.debug_cropping, bm.save_cropped, img_data, bm.x_range, bm.y_range, bm.z_range)
|
292
293
|
|
293
|
-
# load prediction data
|
294
|
-
img, img_header, z_shape, y_shape, x_shape, region_of_interest, img_data = load_prediction_data(bm.path_to_image,
|
295
|
-
channels, bm.x_scale, bm.y_scale, bm.z_scale, bm.no_scaling, normalize, normalization_parameters,
|
296
|
-
region_of_interest, img_data, img_header)
|
297
|
-
|
298
294
|
# make prediction
|
299
|
-
results, bm = predict_semantic_segmentation(bm,
|
300
|
-
|
301
|
-
|
302
|
-
|
295
|
+
results, bm = predict_semantic_segmentation(bm,
|
296
|
+
header, img_header,
|
297
|
+
region_of_interest, extension, img_data,
|
298
|
+
channels, normalization_parameters)
|
303
299
|
|
304
300
|
# results
|
305
301
|
if cropped_volume is not None:
|
@@ -403,7 +399,7 @@ if __name__ == '__main__':
|
|
403
399
|
help='Dice loss function')
|
404
400
|
parser.add_argument('-ad','--average_dice', action='store_true', default=False,
|
405
401
|
help='Use averaged dice score of each label')
|
406
|
-
parser.add_argument('-nc', '--
|
402
|
+
parser.add_argument('-nc', '--no-compression', dest='compression', action='store_false',
|
407
403
|
help='Disable compression of segmentation results')
|
408
404
|
parser.add_argument('-i', '--ignore', type=str, default='none',
|
409
405
|
help='Ignore specific label(s), e.g. 2,5,6')
|
@@ -421,12 +417,12 @@ if __name__ == '__main__':
|
|
421
417
|
help='Epochs the network is trained')
|
422
418
|
parser.add_argument('-ce','--cropping_epochs', type=int, default=50,
|
423
419
|
help='Epochs the network for auto-cropping is trained')
|
424
|
-
parser.add_argument('-nn','--
|
425
|
-
help='Disable image
|
420
|
+
parser.add_argument('-nn','--no-normalization', dest='normalization', action='store_false',
|
421
|
+
help='Disable normalization of 3D image volumes')
|
426
422
|
parser.add_argument('-r','--rotate', type=float, default=0.0,
|
427
423
|
help='Randomly rotate during training')
|
428
424
|
parser.add_argument('-vs','--validation_split', type=float, default=0.0,
|
429
|
-
help='Percentage of data used for
|
425
|
+
help='Percentage of data used for training')
|
430
426
|
parser.add_argument('-lr','--learning_rate', type=float, default=0.01,
|
431
427
|
help='Learning rate')
|
432
428
|
parser.add_argument('-ss','--stride_size', metavar="[1-64]", type=int, choices=range(1,65), default=32,
|
@@ -447,7 +443,7 @@ if __name__ == '__main__':
|
|
447
443
|
help='Images and labels are scaled at y-axis to this size before training')
|
448
444
|
parser.add_argument('-zs','--z_scale', type=int, default=256,
|
449
445
|
help='Images and labels are scaled at z-axis to this size before training')
|
450
|
-
parser.add_argument('-ns','--
|
446
|
+
parser.add_argument('-ns','--no-scaling', dest='scaling', action='store_false',
|
451
447
|
help='Do not resize image and label data')
|
452
448
|
parser.add_argument('-es','--early_stopping', type=int, default=0,
|
453
449
|
help='Training is terminated when the accuracy has not increased in the epochs defined by this')
|
@@ -483,9 +479,18 @@ if __name__ == '__main__':
|
|
483
479
|
help='Processing queue when using a remote server')
|
484
480
|
parser.add_argument('-hf','--header_file', type=str, metavar='PATH', default=None,
|
485
481
|
help='Location of header file')
|
482
|
+
parser.add_argument('-ext','--extension', type=str, default='.tif',
|
483
|
+
help='Save data for example as NRRD file using --extension=".nrrd"')
|
486
484
|
bm = parser.parse_args()
|
487
|
-
|
488
485
|
bm.success = True
|
486
|
+
|
487
|
+
# prediction or training
|
488
|
+
if not any([bm.train, bm.predict]):
|
489
|
+
bm.predict = False
|
490
|
+
bm.train = True
|
491
|
+
if os.path.splitext(bm.path)[1] == '.h5':
|
492
|
+
bm.predict = True
|
493
|
+
bm.train = False
|
489
494
|
if bm.predict:
|
490
495
|
bm.path_to_labels = None
|
491
496
|
bm.path_to_model = bm.path
|
@@ -286,7 +286,7 @@ class DataGenerator(tf.keras.utils.Sequence):
|
|
286
286
|
|
287
287
|
# patch normalization
|
288
288
|
if self.patch_normalization:
|
289
|
-
tmp_X =
|
289
|
+
tmp_X = tmp_X.copy()
|
290
290
|
for c in range(self.n_channels):
|
291
291
|
tmp_X[:,:,:,c] -= np.mean(tmp_X[:,:,:,c])
|
292
292
|
tmp_X[:,:,:,c] /= max(np.std(tmp_X[:,:,:,c]), 1e-6)
|
@@ -106,7 +106,7 @@ def reduce_blocksize(raw, slices):
|
|
106
106
|
return raw, slices, argmin_z, argmax_z, argmin_y, argmax_y, argmin_x, argmax_x
|
107
107
|
|
108
108
|
def activeContour(data, labelData, alpha=1.0, smooth=1, steps=3,
|
109
|
-
path_to_data=None, path_to_labels=None,
|
109
|
+
path_to_data=None, path_to_labels=None, compression=True,
|
110
110
|
ignore='none', only='all', simple=False,
|
111
111
|
img_id=None, friend_id=None, remote=False):
|
112
112
|
|
@@ -126,12 +126,6 @@ def activeContour(data, labelData, alpha=1.0, smooth=1, steps=3,
|
|
126
126
|
else:
|
127
127
|
bm.django_env = False
|
128
128
|
|
129
|
-
# compression
|
130
|
-
if bm.no_compression:
|
131
|
-
bm.compression = False
|
132
|
-
else:
|
133
|
-
bm.compression = True
|
134
|
-
|
135
129
|
# disable file saving when called as a function
|
136
130
|
if bm.data is not None:
|
137
131
|
bm.path_to_data = None
|
@@ -374,8 +368,7 @@ def init_active_contour(image_id, friend_id, label_id, simple=False):
|
|
374
368
|
else:
|
375
369
|
try:
|
376
370
|
activeContour(None, None, path_to_data=image.pic.path, path_to_labels=friend.pic.path,
|
377
|
-
alpha=label.ac_alpha, smooth=label.ac_smooth, steps=label.ac_steps,
|
378
|
-
no_compression=(False if label.compression else True),
|
371
|
+
alpha=label.ac_alpha, smooth=label.ac_smooth, steps=label.ac_steps, compression=label.compression,
|
379
372
|
simple=simple, img_id=image_id, friend_id=friend_id, remote=False)
|
380
373
|
except Exception as e:
|
381
374
|
print(traceback.format_exc())
|
@@ -407,7 +400,7 @@ if __name__ == '__main__':
|
|
407
400
|
help='Number of smoothing steps')
|
408
401
|
parser.add_argument('-st', '--steps', type=int, default=3,
|
409
402
|
help='Number of iterations')
|
410
|
-
parser.add_argument('-nc', '--
|
403
|
+
parser.add_argument('-nc', '--no-compression', dest='compression', action='store_false',
|
411
404
|
help='Disable compression of segmentation results')
|
412
405
|
parser.add_argument('-i', '--ignore', type=str, default='none',
|
413
406
|
help='Ignore specific label(s), e.g. 2,5,6')
|
@@ -317,19 +317,23 @@ def load_data(path_to_data, process='None', return_extension=False):
|
|
317
317
|
data, header = None, None
|
318
318
|
else:
|
319
319
|
try:
|
320
|
-
#
|
321
|
-
|
322
|
-
|
320
|
+
# load data slice by slice
|
321
|
+
file_names = []
|
322
|
+
img_slices = []
|
323
|
+
header = []
|
324
|
+
files.sort()
|
325
|
+
for file_name in files:
|
326
|
+
if os.path.isfile(file_name):
|
323
327
|
try:
|
324
|
-
img,
|
328
|
+
img, img_header = load(file_name)
|
329
|
+
file_names.append(file_name)
|
330
|
+
img_slices.append(img)
|
331
|
+
header.append(img_header)
|
325
332
|
except:
|
326
|
-
|
327
|
-
else:
|
328
|
-
files.remove(name)
|
329
|
-
files.sort()
|
333
|
+
pass
|
330
334
|
|
331
335
|
# get data size
|
332
|
-
img
|
336
|
+
img = img_slices[0]
|
333
337
|
if len(img.shape)==3:
|
334
338
|
ysh, xsh, csh = img.shape[0], img.shape[1], img.shape[2]
|
335
339
|
channel = 'last'
|
@@ -340,11 +344,9 @@ def load_data(path_to_data, process='None', return_extension=False):
|
|
340
344
|
ysh, xsh = img.shape[0], img.shape[1]
|
341
345
|
csh, channel = 0, None
|
342
346
|
|
343
|
-
#
|
344
|
-
data = np.empty((len(
|
345
|
-
|
346
|
-
for k, file_name in enumerate(files):
|
347
|
-
img, img_header = load(file_name)
|
347
|
+
# create 3D volume
|
348
|
+
data = np.empty((len(file_names), ysh, xsh), dtype=img.dtype)
|
349
|
+
for k, img in enumerate(img_slices):
|
348
350
|
if csh==3:
|
349
351
|
img = rgb2gray(img, channel)
|
350
352
|
elif csh==1 and channel=='last':
|
@@ -352,8 +354,7 @@ def load_data(path_to_data, process='None', return_extension=False):
|
|
352
354
|
elif csh==1 and channel=='first':
|
353
355
|
img = img[0,:,:]
|
354
356
|
data[k] = img
|
355
|
-
|
356
|
-
header = [header, files, data.dtype]
|
357
|
+
header = [header, file_names, data.dtype]
|
357
358
|
data = np.swapaxes(data, 1, 2)
|
358
359
|
data = np.copy(data, order='C')
|
359
360
|
except Exception as e:
|
@@ -415,25 +416,33 @@ def pre_processing(bm):
|
|
415
416
|
if bm.labelData is None:
|
416
417
|
return _error_(bm, 'Invalid label data.')
|
417
418
|
|
419
|
+
# dimension errors
|
418
420
|
if len(bm.labelData.shape) != 3:
|
419
|
-
return _error_(bm, 'Label must be three-dimensional.')
|
420
|
-
|
421
|
+
return _error_(bm, 'Label data must be three-dimensional.')
|
421
422
|
if bm.data.shape != bm.labelData.shape:
|
422
|
-
return _error_(bm, 'Image and label must have the same x,y,z-dimensions.')
|
423
|
+
return _error_(bm, 'Image and label data must have the same x,y,z-dimensions.')
|
424
|
+
|
425
|
+
# label data type
|
426
|
+
if bm.labelData.dtype in ['float16','float32','float64']:
|
427
|
+
if bm.django_env:
|
428
|
+
return _error_(bm, 'Label data must be of integer type.')
|
429
|
+
print(f'Warning: Potential label loss during conversion from {bm.labelData.dtype} to int32.')
|
430
|
+
bm.labelData = bm.labelData.astype(np.int32)
|
423
431
|
|
424
432
|
# get labels
|
425
433
|
bm.allLabels = np.unique(bm.labelData)
|
426
434
|
index = np.argwhere(bm.allLabels<0)
|
427
435
|
bm.allLabels = np.delete(bm.allLabels, index)
|
428
436
|
|
429
|
-
|
430
|
-
return _error_(bm, 'No labels higher than 255 allowed.')
|
431
|
-
|
437
|
+
# labels greater than 255
|
432
438
|
if np.any(bm.allLabels > 255):
|
433
|
-
bm.
|
434
|
-
|
435
|
-
|
436
|
-
|
439
|
+
if bm.django_env:
|
440
|
+
return _error_(bm, 'No labels greater than 255 allowed.')
|
441
|
+
else:
|
442
|
+
bm.labelData[bm.labelData > 255] = 0
|
443
|
+
index = np.argwhere(bm.allLabels > 255)
|
444
|
+
bm.allLabels = np.delete(bm.allLabels, index)
|
445
|
+
print('Warning: Only labels <=255 are allowed. Labels greater than 255 will be removed.')
|
437
446
|
|
438
447
|
# add background label if not existing
|
439
448
|
if not np.any(bm.allLabels==0):
|
@@ -485,7 +494,8 @@ def save_data(path_to_final, final, header=None, final_image_type=None, compress
|
|
485
494
|
np_to_nc(path_to_final, final, header)
|
486
495
|
elif final_image_type in ['.hdr', '.mhd', '.mha', '.nrrd', '.nii', '.nii.gz']:
|
487
496
|
simg = sitk.GetImageFromArray(final)
|
488
|
-
|
497
|
+
if header is not None:
|
498
|
+
simg.CopyInformation(header)
|
489
499
|
sitk.WriteImage(simg, path_to_final, useCompression=compress)
|
490
500
|
elif final_image_type in ['.zip', 'directory', '']:
|
491
501
|
with tempfile.TemporaryDirectory() as temp_dir:
|
@@ -151,6 +151,7 @@ def create_slices(path_to_data, path_to_label, on_site=False):
|
|
151
151
|
# increase contrast
|
152
152
|
raw = img_to_uint8(raw)
|
153
153
|
raw = contrast(raw)
|
154
|
+
zsh, ysh, xsh = raw.shape
|
154
155
|
|
155
156
|
# create slices for slice viewer
|
156
157
|
if not os.path.isdir(path_to_slices):
|
@@ -160,9 +161,9 @@ def create_slices(path_to_data, path_to_label, on_site=False):
|
|
160
161
|
os.chmod(path_to_slices, 0o770)
|
161
162
|
|
162
163
|
# save slices
|
163
|
-
for k in range(
|
164
|
+
for k in range(zsh):
|
164
165
|
im = Image.fromarray(raw[k])
|
165
|
-
im.save(path_to_slices +
|
166
|
+
im.save(path_to_slices + '/slice_' + str(k).zfill(len(str(zsh-1))) + '.png')
|
166
167
|
|
167
168
|
if path_to_label and not os.path.isdir(path_to_label_slices):
|
168
169
|
|
@@ -263,7 +264,7 @@ def create_slices(path_to_data, path_to_label, on_site=False):
|
|
263
264
|
|
264
265
|
# save slice
|
265
266
|
im = Image.fromarray(out)
|
266
|
-
im.save(path_to_label_slices +
|
267
|
+
im.save(path_to_label_slices + '/slice_' + str(k).zfill(len(str(zsh-1))) + '.png')
|
267
268
|
|
268
269
|
except Exception as e:
|
269
270
|
print(e)
|
@@ -542,7 +542,8 @@ def load_and_train(normalize,path_to_img,path_to_labels,path_to_model,
|
|
542
542
|
cropping_weights.append(arr)
|
543
543
|
|
544
544
|
# configuration data
|
545
|
-
cropping_config = np.array([channels, x_scale, y_scale, z_scale, normalize,
|
545
|
+
cropping_config = np.array([channels, x_scale, y_scale, z_scale, normalize,
|
546
|
+
normalization_parameters[0,0], normalization_parameters[1,0]])
|
546
547
|
|
547
548
|
return cropping_weights, cropping_config, normalization_parameters
|
548
549
|
|