Skip to content

Commit 569226d

Browse files
committed
Improve tutorials
1 parent 2a7480f commit 569226d

File tree

3 files changed

+230
-0
lines changed

3 files changed

+230
-0
lines changed

docs/tutorials/augmentation.md

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
# Augmentation pipelines
2+
3+
This tutorial shows how to build data augmentation pipelines with
4+
TorchIO transforms. You will learn how to apply spatial, intensity,
5+
and artifact transforms, compose them into pipelines, and use
6+
`Choice` for discrete parameter sampling.
7+
8+
## A simple pipeline
9+
10+
<!-- pytest-codeblocks:skip -->
11+
```python
12+
import torchio as tio
13+
14+
augmentation = tio.Compose([
15+
tio.Flip(axes=(0, 1, 2), flip_probability=0.5),
16+
tio.Affine(degrees=10, translation=5),
17+
tio.Noise(std=(0.01, 0.1)),
18+
tio.Gamma(log_gamma=(-0.3, 0.3)),
19+
])
20+
21+
subject = tio.Subject(
22+
t1=tio.ScalarImage("t1.nii.gz"),
23+
seg=tio.LabelMap("seg.nii.gz"),
24+
)
25+
augmented = augmentation(subject)
26+
```
27+
28+
Every call to `augmentation(subject)` produces a different result.
29+
Spatial transforms (Flip, Affine) are applied consistently to all
30+
images in the subject — the T1 and segmentation are transformed
31+
together.
32+
33+
## Deterministic vs random
34+
35+
The same class handles both cases. A scalar gives a fixed value;
36+
a tuple gives a uniform range:
37+
38+
<!-- pytest-codeblocks:skip -->
39+
```python
40+
# Always rotate 90°
41+
tio.Affine(degrees=90)
42+
43+
# Rotate uniformly between -15° and 15°
44+
tio.Affine(degrees=15)
45+
46+
# Rotate uniformly between 5° and 20°
47+
tio.Affine(degrees=(5, 20))
48+
```
49+
50+
For discrete choices, use `Choice`:
51+
52+
<!-- pytest-codeblocks:skip -->
53+
```python
54+
# Rotate by exactly -90, 0, 90, or 180 degrees
55+
tio.Affine(degrees=tio.Choice([-90, 0, 90, 180]))
56+
```
57+
58+
You can mix `Choice`, ranges, and fixed values per axis:
59+
60+
<!-- pytest-codeblocks:skip -->
61+
```python
62+
# Fixed along I, random along J, discrete along K
63+
tio.Affine(degrees=(0, (-10, 10), tio.Choice([-90, 0, 90])))
64+
```
65+
66+
## Probability control
67+
68+
Every transform has a `p` parameter (probability of being applied):
69+
70+
<!-- pytest-codeblocks:skip -->
71+
```python
72+
# 50% chance of adding noise
73+
tio.Noise(std=0.1, p=0.5)
74+
```
75+
76+
## Composition strategies
77+
78+
### Compose — apply all in sequence
79+
80+
<!-- pytest-codeblocks:skip -->
81+
```python
82+
pipeline = tio.Compose([
83+
tio.Affine(degrees=10),
84+
tio.Noise(std=0.05),
85+
tio.Gamma(log_gamma=0.3),
86+
])
87+
```
88+
89+
### OneOf — pick one at random
90+
91+
<!-- pytest-codeblocks:skip -->
92+
```python
93+
artifact = tio.OneOf({
94+
tio.Ghosting(intensity=0.5): 0.4,
95+
tio.Spike(intensity=1.0): 0.3,
96+
tio.Motion(degrees=5): 0.3,
97+
})
98+
```
99+
100+
### SomeOf — pick N at random
101+
102+
<!-- pytest-codeblocks:skip -->
103+
```python
104+
augment = tio.SomeOf(
105+
[
106+
tio.Flip(axes=(0, 1, 2)),
107+
tio.Blur(std=1.0),
108+
tio.Noise(std=0.05),
109+
tio.Gamma(log_gamma=0.3),
110+
],
111+
num_transforms=(1, 3), # apply 1 to 3 of the 4
112+
)
113+
```
114+
115+
### Operator sugar
116+
117+
You can use `+` for Compose and `|` for OneOf:
118+
119+
<!-- pytest-codeblocks:skip -->
120+
```python
121+
pipeline = tio.Flip(axes=(0,)) + tio.Noise(std=0.05) + tio.Gamma()
122+
artifact = tio.Ghosting() | tio.Spike() | tio.Motion()
123+
```
124+
125+
## Preprocessing + augmentation
126+
127+
A common pattern separates preprocessing (applied once) from
128+
augmentation (applied each epoch):
129+
130+
<!-- pytest-codeblocks:skip -->
131+
```python
132+
preprocessing = tio.Compose([
133+
tio.Resample(target=1.0), # isotropic 1mm
134+
tio.CropOrPad(target_shape=128), # fixed shape
135+
tio.Normalize(out_min=-1, out_max=1), # rescale to [-1, 1]
136+
])
137+
138+
augmentation = tio.Compose([
139+
tio.Flip(axes=(0, 1, 2), flip_probability=0.5),
140+
tio.Affine(degrees=15, translation=5, p=0.8),
141+
tio.OneOf({
142+
tio.Noise(std=(0.01, 0.1)): 0.5,
143+
tio.Blur(std=(0.5, 2.0)): 0.3,
144+
tio.BiasField(coefficients=0.5): 0.2,
145+
}),
146+
tio.Gamma(log_gamma=(-0.3, 0.3), p=0.5),
147+
])
148+
149+
full_pipeline = preprocessing + augmentation
150+
```
151+
152+
## MRI artifact simulation
153+
154+
TorchIO includes several MRI-specific artifact transforms:
155+
156+
<!-- pytest-codeblocks:skip -->
157+
```python
158+
artifacts = tio.Compose([
159+
tio.Motion(degrees=5, num_transforms=2, p=0.3),
160+
tio.Ghosting(num_ghosts=5, intensity=0.5, p=0.3),
161+
tio.Spike(num_spikes=1, intensity=1.5, p=0.2),
162+
tio.Anisotropy(downsampling=3, p=0.3),
163+
tio.BiasField(coefficients=0.5, p=0.3),
164+
])
165+
```
166+
167+
These are useful for training models that are robust to common MRI
168+
acquisition artifacts.
169+
170+
## Label-aware transforms
171+
172+
Some transforms only affect label maps:
173+
174+
<!-- pytest-codeblocks:skip -->
175+
```python
176+
label_pipeline = tio.Compose([
177+
tio.SequentialLabels(), # renumber to 0, 1, 2, ...
178+
tio.RemoveLabels([4, 5]), # drop unwanted labels
179+
tio.KeepLargestComponent(labels=[1]), # clean up label 1
180+
])
181+
```
182+
183+
## SynthSeg-style synthesis
184+
185+
Generate synthetic images from label maps:
186+
187+
<!-- pytest-codeblocks:skip -->
188+
```python
189+
synth = tio.Compose([
190+
tio.LabelsToImage(label_key="seg"),
191+
tio.Blur(std=(0.5, 1.5)),
192+
tio.BiasField(coefficients=0.5),
193+
tio.Gamma(log_gamma=(-0.3, 0.3)),
194+
tio.Noise(std=(0.01, 0.05)),
195+
])
196+
```
197+
198+
## Summary
199+
200+
| Goal | Transform(s) |
201+
|------|-------------|
202+
| Random flipping | `Flip` |
203+
| Rotation / scaling / shearing | `Affine` |
204+
| Elastic deformation | `ElasticDeformation` |
205+
| Change resolution | `Resample`, `Resize` |
206+
| Fixed shape | `CropOrPad` |
207+
| Intensity normalization | `Normalize`, `Standardize`, `HistogramStandardization` |
208+
| Gaussian noise | `Noise` |
209+
| Gaussian blur | `Blur` |
210+
| Gamma correction | `Gamma` |
211+
| Bias field | `BiasField` |
212+
| MRI motion | `Motion` |
213+
| MRI ghosting | `Ghosting` |
214+
| K-space spikes | `Spike` |
215+
| Simulate low-res axis | `Anisotropy` |
216+
| Label cleanup | `RemoveLabels`, `KeepLargestComponent`, `SequentialLabels` |
217+
| Synthetic images | `LabelsToImage` |
218+
| Self-supervised | `Swap` |

docs/tutorials/index.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
11
# Tutorials
22

33
Step-by-step walkthroughs to learn TorchIO. Start here if you are new.
4+
5+
- [**Your first pipeline**](first-pipeline.md) — load images, create
6+
subjects, slice, and save
7+
- [**Augmentation pipelines**](augmentation.md) — build data
8+
augmentation pipelines with spatial, intensity, and artifact
9+
transforms
10+
- [**Working with large volumes**](large-volumes.md) — lazy loading,
11+
patch-based workflows, and memory-efficient processing
12+
- [**Working with annotations**](annotations.md) — add points and
13+
bounding boxes to subjects

zensical.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ nav = [
2626
{ Tutorials = [
2727
"tutorials/index.md",
2828
"tutorials/first-pipeline.md",
29+
"tutorials/augmentation.md",
2930
"tutorials/large-volumes.md",
3031
"tutorials/annotations.md",
3132
] },
@@ -35,6 +36,7 @@ nav = [
3536
"how-to/monai.md",
3637
"how-to/custom-reader.md",
3738
"how-to/save-nii-zarr.md",
39+
"how-to/remote-nii-zarr.md",
3840
"how-to/annotations.md",
3941
"how-to/visualization.md",
4042
"how-to/patch-inference.md",

0 commit comments

Comments
 (0)