Skip to content

Commit 8072028

Browse files
wyliNic-Ma
andauthored
86 tutorial updates (#183)
* update nifti read notebook * revise notebook unet_segmentation_3d.ipynb * revise transformations - revise Spacing transforms to rely on the affines only - rectified a few typos * unit testing spacing transformations * update docs * update demo with spacing transform * fixes padding mode spacing * fixes load nifti * 3d transform tutorial * update notebooks * revised spacing, load nifti for readability * update example readme to include 3d transforms * fixes tensor contiguous in spatial transforms, fixes docs * update codecov xml for all branches * [DLMED] update spleen notebook Co-authored-by: Nic Ma <nma@nvidia.com>
1 parent e657db0 commit 8072028

23 files changed

+1667
-610
lines changed

codecov.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ coverage:
55
target: 70%
66
threshold: 10
77
base: parent
8-
branches: null
98
if_no_uploads: error
109
if_not_found: success
1110
if_ci_failed: error
@@ -18,7 +17,6 @@ coverage:
1817
# Allows PRs without tests, overall stats count
1918
threshold: 100
2019
base: auto
21-
branches: null
2220
if_no_uploads: error
2321
if_not_found: success
2422
if_ci_failed: error

examples/README.md

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,17 @@ python -m pip install -U notebook
1010
```
1111

1212
### 2. List of examples
13-
#### 1. [classification_3d](https://github.com/Project-MONAI/MONAI/tree/master/examples/classification_3d)
13+
#### [classification_3d](./classification_3d)
1414
Training and evaluation examples of 3D classification based on DenseNet3D and [IXI dataset](https://brain-development.org/ixi-dataset):
1515
The examples are standard PyTorch programs and have both dictionary-based and array-based transformation versions.
16-
#### 2. [classification_3d_ignite](https://github.com/Project-MONAI/MONAI/tree/master/examples/classification_3d_ignite)
16+
#### [classification_3d_ignite](./classification_3d_ignite)
1717
Training and evaluation examples of 3D classification based on DenseNet3D and [IXI dataset](https://brain-development.org/ixi-dataset):
1818
The examples are PyTorch ignite programs and have both dictionary-based and array-based transformation versions.
19-
#### 3. [notebooks/multi_gpu_test](https://github.com/Project-MONAI/MONAI/blob/master/examples/notebooks/multi_gpu_test.ipynb)
19+
#### [notebooks/multi_gpu_test](./notebooks/multi_gpu_test.ipynb)
2020
This notebook is a quick demo for devices, run the Ignite trainer engine on CPU, GPU and multiple GPUs.
21-
#### 4. [notebooks/nifti_read_example](https://github.com/Project-MONAI/MONAI/blob/master/examples/notebooks/nifti_read_example.ipynb)
21+
#### [notebooks/nifti_read_example](./notebooks/nifti_read_example.ipynb)
2222
Illustrate reading NIfTI files and iterating over image patches of the volumes loaded from them.
23-
#### 5. [notebooks/spleen_segmentation_3d](https://github.com/Project-MONAI/MONAI/blob/master/examples/notebooks/spleen_segmentation_3d.ipynb)
23+
#### [notebooks/spleen_segmentation_3d](./notebooks/spleen_segmentation_3d.ipynb)
2424
This notebook is an end-to-end training and evaluation example of 3D segmentation based on [MSD Spleen dataset](http://medicaldecathlon.com):
2525
The example shows the flexibility of MONAI modules in a PyTorch-based program:
2626
- Transforms for dictionary-based training data structure.
@@ -30,17 +30,20 @@ The example shows the flexibility of MONAI modules in a PyTorch-based program:
3030
- 3D UNet, Dice loss function, Mean Dice metric for 3D segmentation task.
3131
- Sliding window inference.
3232
- Deterministic training for reproducibility.
33-
#### 6. [notebooks/transform_speed](https://github.com/Project-MONAI/MONAI/blob/master/examples/notebooks/transform_speed.ipynb)
33+
#### [notebooks/transform_speed](./notebooks/transform_speed.ipynb)
3434
Illustrate reading NIfTI files and test speed of different transforms on different devices.
35-
#### 7. [notebooks/transforms_demo_2d](https://github.com/Project-MONAI/MONAI/blob/master/examples/notebooks/transforms_demo_2d.ipynb)
36-
This notebook demonstrates the medical domain specific transforms on 2D medical images.
37-
#### 8. [notebooks/unet_segmentation_3d_ignite](https://github.com/Project-MONAI/MONAI/blob/master/examples/notebooks/unet_segmentation_3d_ignite.ipynb)
35+
#### [notebooks/transforms_demo_2d](./notebooks/transforms_demo_2d.ipynb)
36+
This notebook demonstrates the image transformations on histology images using
37+
[the GlaS Contest dataset](https://warwick.ac.uk/fac/sci/dcs/research/tia/glascontest/download/).
38+
#### [notebooks/3d_image_transforms](./notebooks/3D_image_transforms.ipynb)
39+
This notebook demonstrates the transformations on volumetric images.
40+
#### [notebooks/unet_segmentation_3d_ignite](./notebooks/unet_segmentation_3d_ignite.ipynb)
3841
This notebook is an end-to-end training & evaluation example of 3D segmentation based on synthetic dataset.
3942
The example is a PyTorch Ignite program and shows several key features of MONAI,
4043
especially with medical domain specific transforms and event handlers.
41-
#### 9. [segmentation_3d](https://github.com/Project-MONAI/MONAI/tree/master/examples/segmentation_3d)
44+
#### [segmentation_3d](./examples/segmentation_3d)
4245
Training and evaluation examples of 3D segmentation based on UNet3D and synthetic dataset.
4346
The examples are standard PyTorch programs and have both dictionary-based and array-based versions.
44-
#### 10. [segmentation_3d_ignite](https://github.com/Project-MONAI/MONAI/tree/master/examples/segmentation_3d_ignite)
47+
#### [segmentation_3d_ignite](./examples/segmentation_3d_ignite)
4548
Training and evaluation examples of 3D segmentation based on UNet3D and synthetic dataset.
4649
The examples are PyTorch Ignite programs and have both dictionary-base and array-based transformations.

examples/notebooks/3D_image_transforms.ipynb

Lines changed: 702 additions & 0 deletions
Large diffs are not rendered by default.

examples/notebooks/nifti_read_example.ipynb

Lines changed: 28 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,13 @@
1717
{
1818
"name": "stdout",
1919
"output_type": "stream",
20-
"text": "MONAI version: 0.0.1\nPython version: 3.8.1 (default, Jan 8 2020, 22:29:32) [GCC 7.3.0]\nNumpy version: 1.18.1\nPytorch version: 1.4.0\nIgnite version: 0.3.0\n"
20+
"text": [
21+
"MONAI version: 0.0.1\n",
22+
"Python version: 3.5.6 |Anaconda, Inc.| (default, Aug 26 2018, 16:30:03) [GCC 4.2.1 Compatible Clang 4.0.1 (tags/RELEASE_401/final)]\n",
23+
"Numpy version: 1.18.2\n",
24+
"Pytorch version: 1.4.0\n",
25+
"Ignite version: 0.3.0\n"
26+
]
2127
}
2228
],
2329
"source": [
@@ -35,56 +41,18 @@
3541
"\n",
3642
"import torch\n",
3743
"from torch.utils.data import DataLoader\n",
38-
"import monai.transforms.compose as transforms\n",
44+
"from monai.transforms.compose import Compose\n",
3945
"\n",
4046
"import monai\n",
4147
"\n",
42-
"from monai.transforms.utils import rescale_array\n",
4348
"from monai.data.nifti_reader import NiftiDataset\n",
4449
"from monai.transforms import AddChannel, Transpose, Rescale, ToTensor, RandUniformPatch\n",
4550
"from monai.data.grid_dataset import GridPatchDataset\n",
51+
"from monai.data.synthetic import create_test_image_3d\n",
4652
"\n",
4753
"monai.config.print_config()"
4854
]
4955
},
50-
{
51-
"cell_type": "markdown",
52-
"metadata": {},
53-
"source": [
54-
"Define a function for creating test images and segmentations:"
55-
]
56-
},
57-
{
58-
"cell_type": "code",
59-
"execution_count": 2,
60-
"metadata": {},
61-
"outputs": [],
62-
"source": [
63-
"def create_test_image_3d(height, width, depth, numObjs=12, radMax=30, noiseMax=0.0, numSegClasses=5):\n",
64-
" '''Return a noisy 3D image and segmentation.'''\n",
65-
" image = np.zeros((width, height,depth))\n",
66-
"\n",
67-
" for i in range(numObjs):\n",
68-
" x = np.random.randint(radMax, width - radMax)\n",
69-
" y = np.random.randint(radMax, height - radMax)\n",
70-
" z = np.random.randint(radMax, depth - radMax)\n",
71-
" rad = np.random.randint(5, radMax)\n",
72-
" spy, spx, spz = np.ogrid[-x:width - x, -y:height - y, -z:depth - z]\n",
73-
" circle = (spx * spx + spy * spy + spz * spz) <= rad * rad\n",
74-
"\n",
75-
" if numSegClasses > 1:\n",
76-
" image[circle] = np.ceil(np.random.random() * numSegClasses)\n",
77-
" else:\n",
78-
" image[circle] = np.random.random() * 0.5 + 0.5\n",
79-
"\n",
80-
" labels = np.ceil(image).astype(np.int32)\n",
81-
"\n",
82-
" norm = np.random.uniform(0, numSegClasses * noiseMax, size=image.shape)\n",
83-
" noisyimage = rescale_array(np.maximum(image, norm))\n",
84-
"\n",
85-
" return noisyimage, labels"
86-
]
87-
},
8856
{
8957
"cell_type": "markdown",
9058
"metadata": {},
@@ -94,14 +62,14 @@
9462
},
9563
{
9664
"cell_type": "code",
97-
"execution_count": 3,
65+
"execution_count": 2,
9866
"metadata": {},
9967
"outputs": [],
10068
"source": [
10169
"tempdir = tempfile.mkdtemp()\n",
10270
"\n",
10371
"for i in range(5):\n",
104-
" im, seg = create_test_image_3d(256,256,256)\n",
72+
" im, seg = create_test_image_3d(128, 128, 128)\n",
10573
" \n",
10674
" n = nib.Nifti1Image(im, np.eye(4))\n",
10775
" nib.save(n, os.path.join(tempdir, 'im%i.nii.gz'%i))\n",
@@ -119,33 +87,35 @@
11987
},
12088
{
12189
"cell_type": "code",
122-
"execution_count": 5,
90+
"execution_count": 3,
12391
"metadata": {},
12492
"outputs": [
12593
{
12694
"name": "stdout",
12795
"output_type": "stream",
128-
"text": "torch.Size([5, 1, 64, 64, 64]) torch.Size([5, 256, 256, 256])\n"
96+
"text": [
97+
"torch.Size([5, 1, 64, 64, 64]) torch.Size([5, 1, 64, 64, 64])\n"
98+
]
12999
}
130100
],
131101
"source": [
132102
"images = sorted(glob(os.path.join(tempdir,'im*.nii.gz')))\n",
133103
"segs = sorted(glob(os.path.join(tempdir,'seg*.nii.gz')))\n",
134104
"\n",
135-
"imtrans=transforms.Compose([\n",
105+
"imtrans = Compose([\n",
136106
" Rescale(),\n",
137107
" AddChannel(),\n",
138108
" RandUniformPatch((64, 64, 64)),\n",
139109
" ToTensor()\n",
140110
"]) \n",
141111
"\n",
142-
"segtrans=transforms.Compose([\n",
112+
"segtrans = Compose([\n",
143113
" AddChannel(),\n",
144114
" RandUniformPatch((64, 64, 64)),\n",
145115
" ToTensor()\n",
146116
"]) \n",
147117
" \n",
148-
"ds = NiftiDataset(images, segs, imtrans, segtrans)\n",
118+
"ds = NiftiDataset(images, segs, transform=imtrans, seg_transform=segtrans)\n",
149119
"\n",
150120
"loader = DataLoader(ds, batch_size=10, num_workers=2, pin_memory=torch.cuda.is_available())\n",
151121
"im, seg = monai.utils.misc.first(loader)\n",
@@ -161,28 +131,30 @@
161131
},
162132
{
163133
"cell_type": "code",
164-
"execution_count": 7,
134+
"execution_count": 4,
165135
"metadata": {},
166136
"outputs": [
167137
{
168138
"name": "stdout",
169139
"output_type": "stream",
170-
"text": "torch.Size([10, 1, 64, 64, 64]) torch.Size([10, 256, 64, 64])\n"
140+
"text": [
141+
"torch.Size([10, 1, 64, 64, 64]) torch.Size([10, 1, 64, 64, 64])\n"
142+
]
171143
}
172144
],
173145
"source": [
174-
"imtrans=transforms.Compose([\n",
146+
"imtrans = Compose([\n",
175147
" Rescale(),\n",
176148
" AddChannel(),\n",
177149
" ToTensor()\n",
178150
"]) \n",
179151
"\n",
180-
"segtrans=transforms.Compose([\n",
152+
"segtrans = Compose([\n",
181153
" AddChannel(),\n",
182154
" ToTensor()\n",
183155
"]) \n",
184156
" \n",
185-
"ds = NiftiDataset(images, segs, imtrans, segtrans)\n",
157+
"ds = NiftiDataset(images, segs, transform=imtrans, seg_transform=segtrans)\n",
186158
"ds = GridPatchDataset(ds, (64, 64, 64))\n",
187159
"\n",
188160
"loader = DataLoader(ds, batch_size=10, num_workers=2, pin_memory=torch.cuda.is_available())\n",
@@ -192,7 +164,7 @@
192164
},
193165
{
194166
"cell_type": "code",
195-
"execution_count": 8,
167+
"execution_count": 5,
196168
"metadata": {},
197169
"outputs": [],
198170
"source": [
@@ -223,9 +195,9 @@
223195
"name": "python",
224196
"nbconvert_exporter": "python",
225197
"pygments_lexer": "ipython3",
226-
"version": "3.8.1-final"
198+
"version": "3.5.6"
227199
}
228200
},
229201
"nbformat": 4,
230202
"nbformat_minor": 4
231-
}
203+
}

examples/notebooks/spleen_segmentation_3d.ipynb

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@
7070
"import monai\n",
7171
"import monai.transforms.compose as transforms\n",
7272
"from monai.transforms.composables import \\\n",
73-
" LoadNiftid, AddChanneld, ScaleIntensityRanged, RandCropByPosNegLabeld, RandAffined\n",
73+
" LoadNiftid, AddChanneld, ScaleIntensityRanged, RandCropByPosNegLabeld, \\\n",
74+
" RandAffined, Spacingd, Orientationd\n",
7475
"from monai.data.utils import list_data_collate\n",
7576
"from monai.utils.sliding_window_inference import sliding_window_inference\n",
7677
"from monai.metrics.compute_meandice import compute_meandice\n",
@@ -115,6 +116,8 @@
115116
"train_transforms = transforms.Compose([\n",
116117
" LoadNiftid(keys=['image', 'label']),\n",
117118
" AddChanneld(keys=['image', 'label']),\n",
119+
" Spacingd(keys=['image', 'label'], pixdim=(1.5, 1.5, 2.), interp_order=(3, 0)),\n",
120+
" Orientationd(keys=['image', 'label'], axcodes='RAS'),\n",
118121
" ScaleIntensityRanged(keys=['image'], a_min=-57, a_max=164, b_min=0.0, b_max=1.0, clip=True),\n",
119122
" # randomly crop out patch samples from big image based on pos / neg ratio\n",
120123
" # the image centers of negative samples must be in valid image area\n",
@@ -127,6 +130,8 @@
127130
"val_transforms = transforms.Compose([\n",
128131
" LoadNiftid(keys=['image', 'label']),\n",
129132
" AddChanneld(keys=['image', 'label']),\n",
133+
" Spacingd(keys=['image', 'label'], pixdim=(1.5, 1.5, 2.), interp_order=(3, 0)),\n",
134+
" Orientationd(keys=['image', 'label'], axcodes='RAS'),\n",
130135
" ScaleIntensityRanged(keys=['image'], a_min=-57, a_max=164, b_min=0.0, b_max=1.0, clip=True)\n",
131136
"])"
132137
]
@@ -516,4 +521,4 @@
516521
},
517522
"nbformat": 4,
518523
"nbformat_minor": 4
519-
}
524+
}

examples/notebooks/transforms_demo_2d.ipynb

Lines changed: 30 additions & 14 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)