medaugmentx 0.2.0__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.
- medaugmentx-0.2.0/LICENSE +21 -0
- medaugmentx-0.2.0/PKG-INFO +330 -0
- medaugmentx-0.2.0/README.md +273 -0
- medaugmentx-0.2.0/medaugmentx/__init__.py +22 -0
- medaugmentx-0.2.0/medaugmentx/core/__init__.py +16 -0
- medaugmentx-0.2.0/medaugmentx/core/base.py +81 -0
- medaugmentx-0.2.0/medaugmentx/core/compose.py +195 -0
- medaugmentx-0.2.0/medaugmentx/core/utils.py +87 -0
- medaugmentx-0.2.0/medaugmentx/core/volume.py +117 -0
- medaugmentx-0.2.0/medaugmentx/io/__init__.py +18 -0
- medaugmentx-0.2.0/medaugmentx/io/dicom.py +195 -0
- medaugmentx-0.2.0/medaugmentx/io/nifti.py +101 -0
- medaugmentx-0.2.0/medaugmentx/presets.py +226 -0
- medaugmentx-0.2.0/medaugmentx/serialization.py +267 -0
- medaugmentx-0.2.0/medaugmentx/transforms/__init__.py +54 -0
- medaugmentx-0.2.0/medaugmentx/transforms/intensity/__init__.py +18 -0
- medaugmentx-0.2.0/medaugmentx/transforms/intensity/bias_field.py +107 -0
- medaugmentx-0.2.0/medaugmentx/transforms/intensity/blur.py +165 -0
- medaugmentx-0.2.0/medaugmentx/transforms/intensity/brightness_contrast.py +91 -0
- medaugmentx-0.2.0/medaugmentx/transforms/intensity/contrast.py +79 -0
- medaugmentx-0.2.0/medaugmentx/transforms/intensity/noise.py +130 -0
- medaugmentx-0.2.0/medaugmentx/transforms/intensity/window_level.py +116 -0
- medaugmentx-0.2.0/medaugmentx/transforms/modality/__init__.py +22 -0
- medaugmentx-0.2.0/medaugmentx/transforms/modality/ct/__init__.py +4 -0
- medaugmentx-0.2.0/medaugmentx/transforms/modality/ct/beam_hardening.py +108 -0
- medaugmentx-0.2.0/medaugmentx/transforms/modality/mri/__init__.py +5 -0
- medaugmentx-0.2.0/medaugmentx/transforms/modality/mri/ghosting.py +112 -0
- medaugmentx-0.2.0/medaugmentx/transforms/modality/mri/kspace.py +105 -0
- medaugmentx-0.2.0/medaugmentx/transforms/modality/tomosynthesis/__init__.py +12 -0
- medaugmentx-0.2.0/medaugmentx/transforms/modality/tomosynthesis/blur.py +89 -0
- medaugmentx-0.2.0/medaugmentx/transforms/modality/tomosynthesis/dropout.py +82 -0
- medaugmentx-0.2.0/medaugmentx/transforms/modality/tomosynthesis/elastic.py +70 -0
- medaugmentx-0.2.0/medaugmentx/transforms/modality/tomosynthesis/slab.py +89 -0
- medaugmentx-0.2.0/medaugmentx/transforms/spatial/__init__.py +7 -0
- medaugmentx-0.2.0/medaugmentx/transforms/spatial/affine.py +187 -0
- medaugmentx-0.2.0/medaugmentx/transforms/spatial/crop.py +112 -0
- medaugmentx-0.2.0/medaugmentx/transforms/spatial/elastic.py +133 -0
- medaugmentx-0.2.0/medaugmentx/transforms/spatial/flip.py +75 -0
- medaugmentx-0.2.0/medaugmentx.egg-info/PKG-INFO +330 -0
- medaugmentx-0.2.0/medaugmentx.egg-info/SOURCES.txt +45 -0
- medaugmentx-0.2.0/medaugmentx.egg-info/dependency_links.txt +1 -0
- medaugmentx-0.2.0/medaugmentx.egg-info/requires.txt +32 -0
- medaugmentx-0.2.0/medaugmentx.egg-info/top_level.txt +1 -0
- medaugmentx-0.2.0/pyproject.toml +107 -0
- medaugmentx-0.2.0/setup.cfg +4 -0
- medaugmentx-0.2.0/tests/test_presets.py +141 -0
- medaugmentx-0.2.0/tests/test_serialization.py +193 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 MedAugment Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: medaugmentx
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Clinically-aware medical image augmentation for AI training (MRI, CT, X-Ray, Tomosynthesis).
|
|
5
|
+
Author: MedAugmentX Contributors
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/medaugmentx/medaugmentx
|
|
8
|
+
Project-URL: Documentation, https://github.com/medaugmentx/medaugmentx/tree/main/docs
|
|
9
|
+
Project-URL: Source, https://github.com/medaugmentx/medaugmentx
|
|
10
|
+
Project-URL: Issues, https://github.com/medaugmentx/medaugmentx/issues
|
|
11
|
+
Keywords: medical-imaging,data-augmentation,deep-learning,dicom,nifti,tomosynthesis,mri,ct,radiology-ai
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
24
|
+
Classifier: Topic :: Scientific/Engineering :: Image Processing
|
|
25
|
+
Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
|
|
26
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
27
|
+
Requires-Python: >=3.9
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
License-File: LICENSE
|
|
30
|
+
Requires-Dist: numpy>=1.22
|
|
31
|
+
Requires-Dist: scipy>=1.9
|
|
32
|
+
Provides-Extra: dicom
|
|
33
|
+
Requires-Dist: pydicom>=2.3; extra == "dicom"
|
|
34
|
+
Provides-Extra: nifti
|
|
35
|
+
Requires-Dist: nibabel>=4.0; extra == "nifti"
|
|
36
|
+
Provides-Extra: io
|
|
37
|
+
Requires-Dist: pydicom>=2.3; extra == "io"
|
|
38
|
+
Requires-Dist: nibabel>=4.0; extra == "io"
|
|
39
|
+
Provides-Extra: test
|
|
40
|
+
Requires-Dist: pytest>=7.0; extra == "test"
|
|
41
|
+
Requires-Dist: pytest-cov>=4.0; extra == "test"
|
|
42
|
+
Requires-Dist: hypothesis>=6.70; extra == "test"
|
|
43
|
+
Requires-Dist: pydicom>=2.3; extra == "test"
|
|
44
|
+
Requires-Dist: nibabel>=4.0; extra == "test"
|
|
45
|
+
Provides-Extra: yaml
|
|
46
|
+
Requires-Dist: pyyaml>=6.0; extra == "yaml"
|
|
47
|
+
Provides-Extra: dev
|
|
48
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
49
|
+
Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
50
|
+
Requires-Dist: hypothesis>=6.70; extra == "dev"
|
|
51
|
+
Requires-Dist: pydicom>=2.3; extra == "dev"
|
|
52
|
+
Requires-Dist: nibabel>=4.0; extra == "dev"
|
|
53
|
+
Requires-Dist: pyyaml>=6.0; extra == "dev"
|
|
54
|
+
Requires-Dist: ruff>=0.4; extra == "dev"
|
|
55
|
+
Requires-Dist: mypy>=1.5; extra == "dev"
|
|
56
|
+
Dynamic: license-file
|
|
57
|
+
|
|
58
|
+
# MedAugmentX
|
|
59
|
+
|
|
60
|
+
**Clinically-aware medical image augmentation for AI training.**
|
|
61
|
+
|
|
62
|
+
[](https://www.python.org/downloads/)
|
|
63
|
+
[](LICENSE)
|
|
64
|
+
[](docs/MILESTONES.md)
|
|
65
|
+
|
|
66
|
+
MedAugmentX is a purpose-built Python library for data augmentation of medical
|
|
67
|
+
images. Unlike general-purpose libraries (`torchvision`, `albumentations`), it
|
|
68
|
+
treats the unique properties of medical data — anisotropic 3D volumes,
|
|
69
|
+
modality-specific artifacts, mask consistency, and clinical I/O — as
|
|
70
|
+
first-class concerns.
|
|
71
|
+
|
|
72
|
+
**Zero deep-learning dependencies.** The core library requires only NumPy and
|
|
73
|
+
SciPy. PyTorch, MONAI, and TorchIO interop are planned for Phase 3.
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Why MedAugmentX
|
|
78
|
+
|
|
79
|
+
| Problem with general-purpose augmentation | What MedAugmentX does |
|
|
80
|
+
| --- | --- |
|
|
81
|
+
| Treats every image as 2D RGB | Native 3D volumes with anisotropic-aware ops |
|
|
82
|
+
| No MRI-specific noise or artifact models | Physics-based Rician noise, bias field, k-space corruption, ghosting |
|
|
83
|
+
| CT/DXR augmentation is generic brightness shift | Window/level variation, beam hardening, resolution simulation |
|
|
84
|
+
| Masks drift on complex transforms | Deterministic seeding; image and mask share the same random draw |
|
|
85
|
+
| No tomosynthesis support | Dedicated DBT module with slab-aware augmentations |
|
|
86
|
+
| DICOM/NIfTI I/O scattered across libraries | One loader, one `MedVolume`, vendor metadata preserved |
|
|
87
|
+
| Pipelines can't be saved or reloaded | Full JSON/YAML serialisation with round-trip reconstruction |
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Install
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
# Core (NumPy + SciPy only)
|
|
95
|
+
pip install medaugmentx
|
|
96
|
+
|
|
97
|
+
# With DICOM/NIfTI I/O
|
|
98
|
+
pip install "medaugmentx[io]"
|
|
99
|
+
|
|
100
|
+
# With YAML serialisation support
|
|
101
|
+
pip install "medaugmentx[yaml]"
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Verify the installation:
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
import medaugmentx
|
|
108
|
+
print(medaugmentx.__version__) # 0.2.0
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Quick start
|
|
114
|
+
|
|
115
|
+
### One-line preset
|
|
116
|
+
|
|
117
|
+
The fastest way to get started is a pre-built modality preset:
|
|
118
|
+
|
|
119
|
+
```python
|
|
120
|
+
from medaugmentx.presets import mri_pipeline, ct_pipeline, dxr_pipeline, dbt_pipeline
|
|
121
|
+
|
|
122
|
+
pipeline = mri_pipeline(seed=42)
|
|
123
|
+
augmented = pipeline(vol) # MedVolume in, MedVolume out
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Four presets ship out of the box — see [Preset pipelines](#preset-pipelines) below.
|
|
127
|
+
|
|
128
|
+
### Build your own pipeline
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
import numpy as np
|
|
132
|
+
from medaugmentx import MedVolume, Compose, OneOf
|
|
133
|
+
from medaugmentx.transforms import (
|
|
134
|
+
RandomAffine, ElasticDeform,
|
|
135
|
+
BiasField, RicianNoise, GaussianNoise, GammaCorrection,
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
vol = MedVolume(
|
|
139
|
+
image=np.random.rand(80, 256, 256).astype(np.float32),
|
|
140
|
+
mask=np.zeros((80, 256, 256), dtype=np.uint8),
|
|
141
|
+
spacing=(1.0, 0.7, 0.7), # mm per axis (z, y, x)
|
|
142
|
+
metadata={"modality": "MR"},
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
augment = Compose([
|
|
146
|
+
RandomAffine(rotation=15, scale=(0.9, 1.1), p=0.7),
|
|
147
|
+
ElasticDeform(alpha=(120, 120, 10), sigma=(10, 10, 3), p=0.5),
|
|
148
|
+
BiasField(alpha=0.3, p=0.7),
|
|
149
|
+
OneOf([
|
|
150
|
+
RicianNoise(std=(0.005, 0.02)), # MRI physical noise model
|
|
151
|
+
GaussianNoise(std=0.015), # simpler additive noise
|
|
152
|
+
], p=0.5),
|
|
153
|
+
GammaCorrection(gamma=(0.8, 1.2), p=0.5),
|
|
154
|
+
], seed=42)
|
|
155
|
+
|
|
156
|
+
out = augment(vol) # mask kept in sync automatically
|
|
157
|
+
print(out.image.shape, out.mask.shape)
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Mask values are preserved exactly — spatial transforms use nearest-neighbour
|
|
161
|
+
interpolation for the mask and the same random draw as the image.
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## Preset pipelines
|
|
166
|
+
|
|
167
|
+
Ready-to-use `Compose` pipelines for common modalities. All presets are
|
|
168
|
+
seeded, deterministic, and serialisable.
|
|
169
|
+
|
|
170
|
+
```python
|
|
171
|
+
from medaugmentx.presets import mri_pipeline, ct_pipeline, dxr_pipeline, dbt_pipeline
|
|
172
|
+
|
|
173
|
+
mri = mri_pipeline(seed=42) # bias field, Rician noise, ghosting/k-space
|
|
174
|
+
ct = ct_pipeline(seed=42) # window/level, Gaussian noise, beam hardening
|
|
175
|
+
dxr = dxr_pipeline(seed=42) # blur, brightness/contrast, low-resolution sim
|
|
176
|
+
dbt = dbt_pipeline(seed=42) # slab shift, limited-angle blur, anisotropic elastic
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Each preset is a starting point — tune the parameters or swap transforms for
|
|
180
|
+
your dataset.
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## Serialisation
|
|
185
|
+
|
|
186
|
+
Pipelines serialise to JSON (built-in) or YAML (optional PyYAML):
|
|
187
|
+
|
|
188
|
+
```python
|
|
189
|
+
from medaugmentx.serialization import to_json, from_json
|
|
190
|
+
|
|
191
|
+
pipeline = mri_pipeline(seed=42)
|
|
192
|
+
|
|
193
|
+
# Save
|
|
194
|
+
json_str = to_json(pipeline)
|
|
195
|
+
with open("pipeline.json", "w") as f:
|
|
196
|
+
f.write(json_str)
|
|
197
|
+
|
|
198
|
+
# Reload — exact same structure, ready to run
|
|
199
|
+
pipeline2 = from_json(open("pipeline.json").read())
|
|
200
|
+
out = pipeline2(vol)
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Custom transforms can be added to the registry so they serialise too:
|
|
204
|
+
|
|
205
|
+
```python
|
|
206
|
+
from medaugmentx.serialization import REGISTRY
|
|
207
|
+
REGISTRY["MyTransform"] = MyTransform
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## Loading real volumes
|
|
213
|
+
|
|
214
|
+
```python
|
|
215
|
+
from medaugmentx.io import load_dicom_series, load_nifti, save_nifti
|
|
216
|
+
|
|
217
|
+
vol_ct = load_dicom_series("/path/to/study/CT_chest/") # MedVolume
|
|
218
|
+
vol_mri = load_nifti("brain_t1.nii.gz") # MedVolume
|
|
219
|
+
|
|
220
|
+
augmented = ct_pipeline(seed=0)(vol_ct)
|
|
221
|
+
save_nifti(augmented, "ct_augmented.nii.gz")
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
Both loaders populate `spacing` and `metadata` (modality, vendor, DICOM tags)
|
|
225
|
+
automatically.
|
|
226
|
+
|
|
227
|
+
> Requires the `io` extra: `pip install "medaugmentx[io]"`
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## What's available
|
|
232
|
+
|
|
233
|
+
### Core
|
|
234
|
+
|
|
235
|
+
| Component | Description |
|
|
236
|
+
| --- | --- |
|
|
237
|
+
| `MedVolume` | Container: image + optional mask + spacing + metadata |
|
|
238
|
+
| `Transform` | Abstract base — probability gating, seedable RNG, `to_dict()` |
|
|
239
|
+
| `Compose` | Sequential pipeline with deterministic child seeding |
|
|
240
|
+
| `OneOf` / `SomeOf` | Random selection from a set of transforms |
|
|
241
|
+
|
|
242
|
+
### Spatial transforms
|
|
243
|
+
|
|
244
|
+
| Transform | What it does |
|
|
245
|
+
| --- | --- |
|
|
246
|
+
| `RandomAffine` | Rotation + scaling + translation, 2D/3D, axis-aware |
|
|
247
|
+
| `RandomFlip` | Per-axis flip with independent probability |
|
|
248
|
+
| `AnatomicCrop` | Foreground-biased random crop |
|
|
249
|
+
| `ElasticDeform` | Anisotropic B-spline elastic deformation |
|
|
250
|
+
|
|
251
|
+
### Intensity transforms
|
|
252
|
+
|
|
253
|
+
| Transform | What it does |
|
|
254
|
+
| --- | --- |
|
|
255
|
+
| `GaussianNoise` | Additive zero-mean Gaussian noise |
|
|
256
|
+
| `RicianNoise` | MRI magnitude noise (physically correct for low-SNR regions) |
|
|
257
|
+
| `GammaCorrection` | Power-law contrast, normalisation-aware |
|
|
258
|
+
| `BiasField` | Smooth multiplicative field (MRI coil inhomogeneity) |
|
|
259
|
+
| `WindowLevel` | Random CT window/level shift (protocol variation) |
|
|
260
|
+
| `BrightnessContrast` | Additive brightness + multiplicative contrast |
|
|
261
|
+
| `GaussianBlur` | Isotropic Gaussian blur |
|
|
262
|
+
| `SimulateLowResolution` | Downsample + upsample (cross-site resolution variation) |
|
|
263
|
+
|
|
264
|
+
### Modality-specific — MRI
|
|
265
|
+
|
|
266
|
+
| Transform | What it does |
|
|
267
|
+
| --- | --- |
|
|
268
|
+
| `GhostingArtifact` | Phase-encoding ghosting (shifted attenuated replica) |
|
|
269
|
+
| `KSpaceDropout` | Random k-space line zeroing with Gibbs ringing reconstruction |
|
|
270
|
+
|
|
271
|
+
### Modality-specific — CT
|
|
272
|
+
|
|
273
|
+
| Transform | What it does |
|
|
274
|
+
| --- | --- |
|
|
275
|
+
| `BeamHardening` | Radially-symmetric cupping artifact |
|
|
276
|
+
|
|
277
|
+
### Modality-specific — Tomosynthesis (DBT)
|
|
278
|
+
|
|
279
|
+
| Transform | What it does |
|
|
280
|
+
| --- | --- |
|
|
281
|
+
| `SlabShift` | Z-axis reconstruction-centre variation |
|
|
282
|
+
| `LimitedAngleBlur` | Arc-angle-dependent Z-only blur |
|
|
283
|
+
| `SliceDropout` | Random slice zeroing (robustness) |
|
|
284
|
+
| `AnisotropicElastic` | DBT-default elastic deformation |
|
|
285
|
+
|
|
286
|
+
### I/O
|
|
287
|
+
|
|
288
|
+
| Helper | Description |
|
|
289
|
+
| --- | --- |
|
|
290
|
+
| `load_dicom_series(path)` | 3D volume from a DICOM series directory |
|
|
291
|
+
| `load_nifti(path)` | MedVolume from `.nii` / `.nii.gz` |
|
|
292
|
+
| `save_nifti(vol, path)` | Write MedVolume to NIfTI |
|
|
293
|
+
|
|
294
|
+
---
|
|
295
|
+
|
|
296
|
+
## Reproducibility
|
|
297
|
+
|
|
298
|
+
Every transform is seedable. `Compose(..., seed=42)` produces bit-identical
|
|
299
|
+
output across runs and across machines (within a NumPy version):
|
|
300
|
+
|
|
301
|
+
```python
|
|
302
|
+
a = Compose([...], seed=42)(vol)
|
|
303
|
+
b = Compose([...], seed=42)(vol)
|
|
304
|
+
assert np.array_equal(a.image, b.image) # always passes
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
---
|
|
308
|
+
|
|
309
|
+
## Project status & roadmap
|
|
310
|
+
|
|
311
|
+
| Phase | Status |
|
|
312
|
+
| --- | --- |
|
|
313
|
+
| **1 — Core MVP** | ✅ Core data model, spatial/intensity transforms, DBT, DICOM/NIfTI I/O |
|
|
314
|
+
| **2 — Modality artifacts & serialisation** | ✅ MRI (bias field, ghosting, k-space), CT (beam hardening), presets, JSON/YAML |
|
|
315
|
+
| **3 — GPU backend, framework interop, v1.0** | Planned |
|
|
316
|
+
|
|
317
|
+
Detailed deliverables: [docs/MILESTONES.md](docs/MILESTONES.md).
|
|
318
|
+
|
|
319
|
+
---
|
|
320
|
+
|
|
321
|
+
## Contributing
|
|
322
|
+
|
|
323
|
+
We welcome PRs — new transforms, vendor DICOM coverage, and bug reports with
|
|
324
|
+
sample data are especially valuable. See [CONTRIBUTING.md](CONTRIBUTING.md)
|
|
325
|
+
for the development setup, testing conventions, and the transform-authoring
|
|
326
|
+
template.
|
|
327
|
+
|
|
328
|
+
## License
|
|
329
|
+
|
|
330
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
# MedAugmentX
|
|
2
|
+
|
|
3
|
+
**Clinically-aware medical image augmentation for AI training.**
|
|
4
|
+
|
|
5
|
+
[](https://www.python.org/downloads/)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
[](docs/MILESTONES.md)
|
|
8
|
+
|
|
9
|
+
MedAugmentX is a purpose-built Python library for data augmentation of medical
|
|
10
|
+
images. Unlike general-purpose libraries (`torchvision`, `albumentations`), it
|
|
11
|
+
treats the unique properties of medical data — anisotropic 3D volumes,
|
|
12
|
+
modality-specific artifacts, mask consistency, and clinical I/O — as
|
|
13
|
+
first-class concerns.
|
|
14
|
+
|
|
15
|
+
**Zero deep-learning dependencies.** The core library requires only NumPy and
|
|
16
|
+
SciPy. PyTorch, MONAI, and TorchIO interop are planned for Phase 3.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Why MedAugmentX
|
|
21
|
+
|
|
22
|
+
| Problem with general-purpose augmentation | What MedAugmentX does |
|
|
23
|
+
| --- | --- |
|
|
24
|
+
| Treats every image as 2D RGB | Native 3D volumes with anisotropic-aware ops |
|
|
25
|
+
| No MRI-specific noise or artifact models | Physics-based Rician noise, bias field, k-space corruption, ghosting |
|
|
26
|
+
| CT/DXR augmentation is generic brightness shift | Window/level variation, beam hardening, resolution simulation |
|
|
27
|
+
| Masks drift on complex transforms | Deterministic seeding; image and mask share the same random draw |
|
|
28
|
+
| No tomosynthesis support | Dedicated DBT module with slab-aware augmentations |
|
|
29
|
+
| DICOM/NIfTI I/O scattered across libraries | One loader, one `MedVolume`, vendor metadata preserved |
|
|
30
|
+
| Pipelines can't be saved or reloaded | Full JSON/YAML serialisation with round-trip reconstruction |
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Install
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
# Core (NumPy + SciPy only)
|
|
38
|
+
pip install medaugmentx
|
|
39
|
+
|
|
40
|
+
# With DICOM/NIfTI I/O
|
|
41
|
+
pip install "medaugmentx[io]"
|
|
42
|
+
|
|
43
|
+
# With YAML serialisation support
|
|
44
|
+
pip install "medaugmentx[yaml]"
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Verify the installation:
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
import medaugmentx
|
|
51
|
+
print(medaugmentx.__version__) # 0.2.0
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Quick start
|
|
57
|
+
|
|
58
|
+
### One-line preset
|
|
59
|
+
|
|
60
|
+
The fastest way to get started is a pre-built modality preset:
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
from medaugmentx.presets import mri_pipeline, ct_pipeline, dxr_pipeline, dbt_pipeline
|
|
64
|
+
|
|
65
|
+
pipeline = mri_pipeline(seed=42)
|
|
66
|
+
augmented = pipeline(vol) # MedVolume in, MedVolume out
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Four presets ship out of the box — see [Preset pipelines](#preset-pipelines) below.
|
|
70
|
+
|
|
71
|
+
### Build your own pipeline
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
import numpy as np
|
|
75
|
+
from medaugmentx import MedVolume, Compose, OneOf
|
|
76
|
+
from medaugmentx.transforms import (
|
|
77
|
+
RandomAffine, ElasticDeform,
|
|
78
|
+
BiasField, RicianNoise, GaussianNoise, GammaCorrection,
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
vol = MedVolume(
|
|
82
|
+
image=np.random.rand(80, 256, 256).astype(np.float32),
|
|
83
|
+
mask=np.zeros((80, 256, 256), dtype=np.uint8),
|
|
84
|
+
spacing=(1.0, 0.7, 0.7), # mm per axis (z, y, x)
|
|
85
|
+
metadata={"modality": "MR"},
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
augment = Compose([
|
|
89
|
+
RandomAffine(rotation=15, scale=(0.9, 1.1), p=0.7),
|
|
90
|
+
ElasticDeform(alpha=(120, 120, 10), sigma=(10, 10, 3), p=0.5),
|
|
91
|
+
BiasField(alpha=0.3, p=0.7),
|
|
92
|
+
OneOf([
|
|
93
|
+
RicianNoise(std=(0.005, 0.02)), # MRI physical noise model
|
|
94
|
+
GaussianNoise(std=0.015), # simpler additive noise
|
|
95
|
+
], p=0.5),
|
|
96
|
+
GammaCorrection(gamma=(0.8, 1.2), p=0.5),
|
|
97
|
+
], seed=42)
|
|
98
|
+
|
|
99
|
+
out = augment(vol) # mask kept in sync automatically
|
|
100
|
+
print(out.image.shape, out.mask.shape)
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Mask values are preserved exactly — spatial transforms use nearest-neighbour
|
|
104
|
+
interpolation for the mask and the same random draw as the image.
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## Preset pipelines
|
|
109
|
+
|
|
110
|
+
Ready-to-use `Compose` pipelines for common modalities. All presets are
|
|
111
|
+
seeded, deterministic, and serialisable.
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
from medaugmentx.presets import mri_pipeline, ct_pipeline, dxr_pipeline, dbt_pipeline
|
|
115
|
+
|
|
116
|
+
mri = mri_pipeline(seed=42) # bias field, Rician noise, ghosting/k-space
|
|
117
|
+
ct = ct_pipeline(seed=42) # window/level, Gaussian noise, beam hardening
|
|
118
|
+
dxr = dxr_pipeline(seed=42) # blur, brightness/contrast, low-resolution sim
|
|
119
|
+
dbt = dbt_pipeline(seed=42) # slab shift, limited-angle blur, anisotropic elastic
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Each preset is a starting point — tune the parameters or swap transforms for
|
|
123
|
+
your dataset.
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## Serialisation
|
|
128
|
+
|
|
129
|
+
Pipelines serialise to JSON (built-in) or YAML (optional PyYAML):
|
|
130
|
+
|
|
131
|
+
```python
|
|
132
|
+
from medaugmentx.serialization import to_json, from_json
|
|
133
|
+
|
|
134
|
+
pipeline = mri_pipeline(seed=42)
|
|
135
|
+
|
|
136
|
+
# Save
|
|
137
|
+
json_str = to_json(pipeline)
|
|
138
|
+
with open("pipeline.json", "w") as f:
|
|
139
|
+
f.write(json_str)
|
|
140
|
+
|
|
141
|
+
# Reload — exact same structure, ready to run
|
|
142
|
+
pipeline2 = from_json(open("pipeline.json").read())
|
|
143
|
+
out = pipeline2(vol)
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Custom transforms can be added to the registry so they serialise too:
|
|
147
|
+
|
|
148
|
+
```python
|
|
149
|
+
from medaugmentx.serialization import REGISTRY
|
|
150
|
+
REGISTRY["MyTransform"] = MyTransform
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## Loading real volumes
|
|
156
|
+
|
|
157
|
+
```python
|
|
158
|
+
from medaugmentx.io import load_dicom_series, load_nifti, save_nifti
|
|
159
|
+
|
|
160
|
+
vol_ct = load_dicom_series("/path/to/study/CT_chest/") # MedVolume
|
|
161
|
+
vol_mri = load_nifti("brain_t1.nii.gz") # MedVolume
|
|
162
|
+
|
|
163
|
+
augmented = ct_pipeline(seed=0)(vol_ct)
|
|
164
|
+
save_nifti(augmented, "ct_augmented.nii.gz")
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Both loaders populate `spacing` and `metadata` (modality, vendor, DICOM tags)
|
|
168
|
+
automatically.
|
|
169
|
+
|
|
170
|
+
> Requires the `io` extra: `pip install "medaugmentx[io]"`
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## What's available
|
|
175
|
+
|
|
176
|
+
### Core
|
|
177
|
+
|
|
178
|
+
| Component | Description |
|
|
179
|
+
| --- | --- |
|
|
180
|
+
| `MedVolume` | Container: image + optional mask + spacing + metadata |
|
|
181
|
+
| `Transform` | Abstract base — probability gating, seedable RNG, `to_dict()` |
|
|
182
|
+
| `Compose` | Sequential pipeline with deterministic child seeding |
|
|
183
|
+
| `OneOf` / `SomeOf` | Random selection from a set of transforms |
|
|
184
|
+
|
|
185
|
+
### Spatial transforms
|
|
186
|
+
|
|
187
|
+
| Transform | What it does |
|
|
188
|
+
| --- | --- |
|
|
189
|
+
| `RandomAffine` | Rotation + scaling + translation, 2D/3D, axis-aware |
|
|
190
|
+
| `RandomFlip` | Per-axis flip with independent probability |
|
|
191
|
+
| `AnatomicCrop` | Foreground-biased random crop |
|
|
192
|
+
| `ElasticDeform` | Anisotropic B-spline elastic deformation |
|
|
193
|
+
|
|
194
|
+
### Intensity transforms
|
|
195
|
+
|
|
196
|
+
| Transform | What it does |
|
|
197
|
+
| --- | --- |
|
|
198
|
+
| `GaussianNoise` | Additive zero-mean Gaussian noise |
|
|
199
|
+
| `RicianNoise` | MRI magnitude noise (physically correct for low-SNR regions) |
|
|
200
|
+
| `GammaCorrection` | Power-law contrast, normalisation-aware |
|
|
201
|
+
| `BiasField` | Smooth multiplicative field (MRI coil inhomogeneity) |
|
|
202
|
+
| `WindowLevel` | Random CT window/level shift (protocol variation) |
|
|
203
|
+
| `BrightnessContrast` | Additive brightness + multiplicative contrast |
|
|
204
|
+
| `GaussianBlur` | Isotropic Gaussian blur |
|
|
205
|
+
| `SimulateLowResolution` | Downsample + upsample (cross-site resolution variation) |
|
|
206
|
+
|
|
207
|
+
### Modality-specific — MRI
|
|
208
|
+
|
|
209
|
+
| Transform | What it does |
|
|
210
|
+
| --- | --- |
|
|
211
|
+
| `GhostingArtifact` | Phase-encoding ghosting (shifted attenuated replica) |
|
|
212
|
+
| `KSpaceDropout` | Random k-space line zeroing with Gibbs ringing reconstruction |
|
|
213
|
+
|
|
214
|
+
### Modality-specific — CT
|
|
215
|
+
|
|
216
|
+
| Transform | What it does |
|
|
217
|
+
| --- | --- |
|
|
218
|
+
| `BeamHardening` | Radially-symmetric cupping artifact |
|
|
219
|
+
|
|
220
|
+
### Modality-specific — Tomosynthesis (DBT)
|
|
221
|
+
|
|
222
|
+
| Transform | What it does |
|
|
223
|
+
| --- | --- |
|
|
224
|
+
| `SlabShift` | Z-axis reconstruction-centre variation |
|
|
225
|
+
| `LimitedAngleBlur` | Arc-angle-dependent Z-only blur |
|
|
226
|
+
| `SliceDropout` | Random slice zeroing (robustness) |
|
|
227
|
+
| `AnisotropicElastic` | DBT-default elastic deformation |
|
|
228
|
+
|
|
229
|
+
### I/O
|
|
230
|
+
|
|
231
|
+
| Helper | Description |
|
|
232
|
+
| --- | --- |
|
|
233
|
+
| `load_dicom_series(path)` | 3D volume from a DICOM series directory |
|
|
234
|
+
| `load_nifti(path)` | MedVolume from `.nii` / `.nii.gz` |
|
|
235
|
+
| `save_nifti(vol, path)` | Write MedVolume to NIfTI |
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## Reproducibility
|
|
240
|
+
|
|
241
|
+
Every transform is seedable. `Compose(..., seed=42)` produces bit-identical
|
|
242
|
+
output across runs and across machines (within a NumPy version):
|
|
243
|
+
|
|
244
|
+
```python
|
|
245
|
+
a = Compose([...], seed=42)(vol)
|
|
246
|
+
b = Compose([...], seed=42)(vol)
|
|
247
|
+
assert np.array_equal(a.image, b.image) # always passes
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## Project status & roadmap
|
|
253
|
+
|
|
254
|
+
| Phase | Status |
|
|
255
|
+
| --- | --- |
|
|
256
|
+
| **1 — Core MVP** | ✅ Core data model, spatial/intensity transforms, DBT, DICOM/NIfTI I/O |
|
|
257
|
+
| **2 — Modality artifacts & serialisation** | ✅ MRI (bias field, ghosting, k-space), CT (beam hardening), presets, JSON/YAML |
|
|
258
|
+
| **3 — GPU backend, framework interop, v1.0** | Planned |
|
|
259
|
+
|
|
260
|
+
Detailed deliverables: [docs/MILESTONES.md](docs/MILESTONES.md).
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
## Contributing
|
|
265
|
+
|
|
266
|
+
We welcome PRs — new transforms, vendor DICOM coverage, and bug reports with
|
|
267
|
+
sample data are especially valuable. See [CONTRIBUTING.md](CONTRIBUTING.md)
|
|
268
|
+
for the development setup, testing conventions, and the transform-authoring
|
|
269
|
+
template.
|
|
270
|
+
|
|
271
|
+
## License
|
|
272
|
+
|
|
273
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""MedAugment — clinically-aware medical image augmentation.
|
|
2
|
+
|
|
3
|
+
Public surface for Phase 2.
|
|
4
|
+
"""
|
|
5
|
+
from medaugmentx.core import (
|
|
6
|
+
Compose,
|
|
7
|
+
MedVolume,
|
|
8
|
+
OneOf,
|
|
9
|
+
SomeOf,
|
|
10
|
+
Transform,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
__version__ = "0.2.0"
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
"__version__",
|
|
17
|
+
"MedVolume",
|
|
18
|
+
"Transform",
|
|
19
|
+
"Compose",
|
|
20
|
+
"OneOf",
|
|
21
|
+
"SomeOf",
|
|
22
|
+
]
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""Core data model and pipeline primitives."""
|
|
2
|
+
from medaugmentx.core.base import Transform
|
|
3
|
+
from medaugmentx.core.compose import Compose, OneOf, SomeOf
|
|
4
|
+
from medaugmentx.core.utils import as_float32, derive_rng, resolve_rng
|
|
5
|
+
from medaugmentx.core.volume import MedVolume
|
|
6
|
+
|
|
7
|
+
__all__ = [
|
|
8
|
+
"MedVolume",
|
|
9
|
+
"Transform",
|
|
10
|
+
"Compose",
|
|
11
|
+
"OneOf",
|
|
12
|
+
"SomeOf",
|
|
13
|
+
"as_float32",
|
|
14
|
+
"derive_rng",
|
|
15
|
+
"resolve_rng",
|
|
16
|
+
]
|