cmpl 0.2.0__tar.gz → 0.2.2__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.
- cmpl-0.2.2/PKG-INFO +567 -0
- cmpl-0.2.2/README.md +496 -0
- {cmpl-0.2.0 → cmpl-0.2.2}/pyproject.toml +1 -1
- cmpl-0.2.2/src/cmpl/dicom/__init__.py +109 -0
- cmpl-0.2.2/src/cmpl/dicom/geometry.py +176 -0
- cmpl-0.2.2/src/cmpl/dicom/metadata.py +132 -0
- {cmpl-0.2.0 → cmpl-0.2.2}/src/cmpl/utilities/io.py +472 -70
- cmpl-0.2.2/src/cmpl.egg-info/PKG-INFO +567 -0
- {cmpl-0.2.0 → cmpl-0.2.2}/src/cmpl.egg-info/SOURCES.txt +2 -0
- {cmpl-0.2.0 → cmpl-0.2.2}/tests/test_installation.py +31 -1
- cmpl-0.2.2/tests/test_io.py +869 -0
- cmpl-0.2.0/PKG-INFO +0 -281
- cmpl-0.2.0/README.md +0 -210
- cmpl-0.2.0/src/cmpl/dicom/__init__.py +0 -33
- cmpl-0.2.0/src/cmpl.egg-info/PKG-INFO +0 -281
- cmpl-0.2.0/tests/test_io.py +0 -395
- {cmpl-0.2.0 → cmpl-0.2.2}/LICENSE +0 -0
- {cmpl-0.2.0 → cmpl-0.2.2}/setup.cfg +0 -0
- {cmpl-0.2.0 → cmpl-0.2.2}/src/cmpl/__init__.py +0 -0
- {cmpl-0.2.0 → cmpl-0.2.2}/src/cmpl/_version.py +0 -0
- {cmpl-0.2.0 → cmpl-0.2.2}/src/cmpl/dicom/enhanced_dicom.py +0 -0
- {cmpl-0.2.0 → cmpl-0.2.2}/src/cmpl/quantitative_MRI/__init__.py +0 -0
- {cmpl-0.2.0 → cmpl-0.2.2}/src/cmpl/quantitative_MRI/mapping.py +0 -0
- {cmpl-0.2.0 → cmpl-0.2.2}/src/cmpl/reconstruction/__init__.py +0 -0
- {cmpl-0.2.0 → cmpl-0.2.2}/src/cmpl/reconstruction/grappa/__init__.py +0 -0
- {cmpl-0.2.0 → cmpl-0.2.2}/src/cmpl/reconstruction/grappa/grappa_1D.py +0 -0
- {cmpl-0.2.0 → cmpl-0.2.2}/src/cmpl/reconstruction/grappa/grappa_2D.py +0 -0
- {cmpl-0.2.0 → cmpl-0.2.2}/src/cmpl/reconstruction/grappa/utils.py +0 -0
- {cmpl-0.2.0 → cmpl-0.2.2}/src/cmpl/reconstruction/sense/__init__.py +0 -0
- {cmpl-0.2.0 → cmpl-0.2.2}/src/cmpl/reconstruction/sense/cg.py +0 -0
- {cmpl-0.2.0 → cmpl-0.2.2}/src/cmpl/segmentation/MRISegmentationTool.py +0 -0
- {cmpl-0.2.0 → cmpl-0.2.2}/src/cmpl/segmentation/__init__.py +0 -0
- {cmpl-0.2.0 → cmpl-0.2.2}/src/cmpl/segmentation/tools.py +0 -0
- {cmpl-0.2.0 → cmpl-0.2.2}/src/cmpl/utilities/__init__.py +0 -0
- {cmpl-0.2.0 → cmpl-0.2.2}/src/cmpl/utilities/df_build.py +0 -0
- {cmpl-0.2.0 → cmpl-0.2.2}/src/cmpl/utilities/numerical.py +0 -0
- {cmpl-0.2.0 → cmpl-0.2.2}/src/cmpl/utilities/utils.py +0 -0
- {cmpl-0.2.0 → cmpl-0.2.2}/src/cmpl/visualization/__init__.py +0 -0
- {cmpl-0.2.0 → cmpl-0.2.2}/src/cmpl/visualization/visualization.py +0 -0
- {cmpl-0.2.0 → cmpl-0.2.2}/src/cmpl.egg-info/dependency_links.txt +0 -0
- {cmpl-0.2.0 → cmpl-0.2.2}/src/cmpl.egg-info/requires.txt +0 -0
- {cmpl-0.2.0 → cmpl-0.2.2}/src/cmpl.egg-info/top_level.txt +0 -0
- {cmpl-0.2.0 → cmpl-0.2.2}/tests/test_data.py +0 -0
- {cmpl-0.2.0 → cmpl-0.2.2}/tests/test_qmr.py +0 -0
- {cmpl-0.2.0 → cmpl-0.2.2}/tests/test_reconstruction.py +0 -0
- {cmpl-0.2.0 → cmpl-0.2.2}/tests/test_visualization.py +0 -0
cmpl-0.2.2/PKG-INFO
ADDED
|
@@ -0,0 +1,567 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cmpl
|
|
3
|
+
Version: 0.2.2
|
|
4
|
+
Summary: CMRR MRI Processing Libraries
|
|
5
|
+
Author: Eisa Hedayati
|
|
6
|
+
License: Copyright (c) 2025 Eisa Hedayati
|
|
7
|
+
|
|
8
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
9
|
+
of this software and associated documentation files (the “Software”), to use,
|
|
10
|
+
copy, modify, merge, publish, distribute, and sublicense copies of the Software,
|
|
11
|
+
subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
1. The Software may **not** be used, in whole or in part, for any purpose that is
|
|
14
|
+
primarily intended for or directed toward commercial advantage or monetary
|
|
15
|
+
compensation.
|
|
16
|
+
|
|
17
|
+
2. The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
22
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
23
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER
|
|
24
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
25
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
Classifier: Programming Language :: Python :: 3
|
|
29
|
+
Classifier: Operating System :: OS Independent
|
|
30
|
+
Classifier: License :: Other/Proprietary License
|
|
31
|
+
Requires-Python: >=3.10
|
|
32
|
+
Description-Content-Type: text/markdown
|
|
33
|
+
License-File: LICENSE
|
|
34
|
+
Requires-Dist: numpy<3,>=1.26
|
|
35
|
+
Requires-Dist: scipy<2,>=1.13
|
|
36
|
+
Requires-Dist: tqdm>=4.66
|
|
37
|
+
Provides-Extra: io
|
|
38
|
+
Requires-Dist: h5py>=3.11; extra == "io"
|
|
39
|
+
Requires-Dist: nibabel<6,>=5.2; extra == "io"
|
|
40
|
+
Requires-Dist: pydicom<4,>=2.4; extra == "io"
|
|
41
|
+
Requires-Dist: SimpleITK>=2.3; extra == "io"
|
|
42
|
+
Provides-Extra: data
|
|
43
|
+
Requires-Dist: pandas<4,>=2.1; extra == "data"
|
|
44
|
+
Provides-Extra: viz
|
|
45
|
+
Requires-Dist: matplotlib>=3.8; extra == "viz"
|
|
46
|
+
Requires-Dist: ipywidgets>=8.1; extra == "viz"
|
|
47
|
+
Requires-Dist: ipython>=8.20; extra == "viz"
|
|
48
|
+
Provides-Extra: torch
|
|
49
|
+
Requires-Dist: torch>=2.2; extra == "torch"
|
|
50
|
+
Provides-Extra: seg
|
|
51
|
+
Requires-Dist: torch>=2.2; extra == "seg"
|
|
52
|
+
Requires-Dist: monai<2,>=1.3; extra == "seg"
|
|
53
|
+
Provides-Extra: all
|
|
54
|
+
Requires-Dist: h5py>=3.11; extra == "all"
|
|
55
|
+
Requires-Dist: pandas<4,>=2.1; extra == "all"
|
|
56
|
+
Requires-Dist: nibabel<6,>=5.2; extra == "all"
|
|
57
|
+
Requires-Dist: pydicom<4,>=2.4; extra == "all"
|
|
58
|
+
Requires-Dist: matplotlib>=3.8; extra == "all"
|
|
59
|
+
Requires-Dist: torch>=2.2; extra == "all"
|
|
60
|
+
Requires-Dist: SimpleITK>=2.3; extra == "all"
|
|
61
|
+
Requires-Dist: dicom2nifti>=2.4; extra == "all"
|
|
62
|
+
Requires-Dist: monai<2,>=1.3; extra == "all"
|
|
63
|
+
Requires-Dist: ipywidgets>=8.1; extra == "all"
|
|
64
|
+
Requires-Dist: ipython>=8.20; extra == "all"
|
|
65
|
+
Provides-Extra: dev
|
|
66
|
+
Requires-Dist: pytest>=8; extra == "dev"
|
|
67
|
+
Requires-Dist: ruff>=0.4.8; extra == "dev"
|
|
68
|
+
Requires-Dist: build; extra == "dev"
|
|
69
|
+
Requires-Dist: twine; extra == "dev"
|
|
70
|
+
Dynamic: license-file
|
|
71
|
+
|
|
72
|
+
# CMPL — CMRR MRI Processing Libraries
|
|
73
|
+
|
|
74
|
+
[](https://pypi.org/project/cmpl/)
|
|
75
|
+
[](https://pypi.org/project/cmpl/)
|
|
76
|
+
|
|
77
|
+
CMPL is a Python package for MRI processing workflows developed at CMRR. It provides tools for MRI reconstruction, quantitative MRI, visualization, DICOM/NIfTI I/O, and supporting numerical/data utilities.
|
|
78
|
+
|
|
79
|
+
CMPL is organized as a modular library: the base installation stays lightweight, while larger or domain-specific dependencies are installed only when the corresponding functionality is needed.
|
|
80
|
+
|
|
81
|
+
## Highlights
|
|
82
|
+
|
|
83
|
+
- Parallel MRI reconstruction with 1D/2D GRAPPA and conjugate-gradient SENSE
|
|
84
|
+
- Quantitative MRI tools for T2* fitting, signal reconstruction, and fitting-error analysis
|
|
85
|
+
- MRI visualization utilities for 2D comparisons, 3D volume browsing, and segmentation overlays
|
|
86
|
+
- DICOM, enhanced-DICOM, NIfTI, and SimpleITK utilities
|
|
87
|
+
- Lightweight numerical utilities shared across CMPL
|
|
88
|
+
- Optional pandas-based indexing for CMPL-style medical-data directory structures
|
|
89
|
+
- Lazy package imports so `import cmpl` does not eagerly load large optional dependencies
|
|
90
|
+
- Backward-compatible convenience aliases such as `cmpl.recon`, `cmpl.qmr`, `cmpl.vis`, and `cmpl.utils`
|
|
91
|
+
|
|
92
|
+
## Requirements
|
|
93
|
+
|
|
94
|
+
CMPL requires:
|
|
95
|
+
|
|
96
|
+
- Python >= 3.10
|
|
97
|
+
- NumPy >= 1.26, < 3
|
|
98
|
+
- SciPy >= 1.13, < 2
|
|
99
|
+
- tqdm >= 4.66
|
|
100
|
+
|
|
101
|
+
Additional dependencies are installed through optional extras.
|
|
102
|
+
|
|
103
|
+
## Installation
|
|
104
|
+
|
|
105
|
+
Install the lightweight base package:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
python -m pip install cmpl
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Install only the functionality you need:
|
|
112
|
+
|
|
113
|
+
| Extra | Purpose |
|
|
114
|
+
| --- | --- |
|
|
115
|
+
| `io` | DICOM, NIfTI, HDF5, and SimpleITK I/O |
|
|
116
|
+
| `data` | pandas-based data indexing |
|
|
117
|
+
| `viz` | Matplotlib and Jupyter visualization |
|
|
118
|
+
| `torch` | PyTorch-based reconstruction and quantitative MRI |
|
|
119
|
+
| `all` | All optional functionality declared by CMPL |
|
|
120
|
+
| `dev` | Testing, linting, build, and release tools |
|
|
121
|
+
|
|
122
|
+
Examples:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
python -m pip install "cmpl[io]"
|
|
126
|
+
python -m pip install "cmpl[viz]"
|
|
127
|
+
python -m pip install "cmpl[torch]"
|
|
128
|
+
python -m pip install "cmpl[io,data,viz,torch]"
|
|
129
|
+
python -m pip install "cmpl[all]"
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Quantitative-MRI fitting currently uses both PyTorch and Matplotlib, so for qMRI workflows install:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
python -m pip install "cmpl[torch,viz]"
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Quick start
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
import cmpl
|
|
142
|
+
|
|
143
|
+
print(cmpl.__version__)
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
CMPL exposes convenient aliases for commonly used subpackages:
|
|
147
|
+
|
|
148
|
+
```python
|
|
149
|
+
cmpl.recon # reconstruction
|
|
150
|
+
cmpl.qmr # quantitative MRI
|
|
151
|
+
cmpl.vis # visualization
|
|
152
|
+
cmpl.utils # utilities
|
|
153
|
+
cmpl.io # I/O utilities
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
The aliases are resolved lazily, so importing CMPL itself does not require every optional dependency to be loaded.
|
|
157
|
+
|
|
158
|
+
## Visualization
|
|
159
|
+
|
|
160
|
+
Install the visualization extra:
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
python -m pip install "cmpl[viz]"
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Browse or display a 3D MRI volume
|
|
167
|
+
|
|
168
|
+
```python
|
|
169
|
+
from cmpl.visualization import plot_3D_mri
|
|
170
|
+
|
|
171
|
+
plot_3D_mri(
|
|
172
|
+
volume,
|
|
173
|
+
slice_number=volume.shape[2] // 2,
|
|
174
|
+
alpha=0.5,
|
|
175
|
+
direction="sagittal",
|
|
176
|
+
cmap="gray",
|
|
177
|
+
vmin=0,
|
|
178
|
+
vmax=1,
|
|
179
|
+
dpi=300,
|
|
180
|
+
)
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
If an interactive Matplotlib backend is available, `plot_3D_mri` can use interactive controls. Otherwise it falls back to static redraw mode.
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
### Compare images side by side
|
|
187
|
+
|
|
188
|
+
```python
|
|
189
|
+
from cmpl.visualization import side_by_side_view
|
|
190
|
+
|
|
191
|
+
side_by_side_view(
|
|
192
|
+
image_a,
|
|
193
|
+
image_b,
|
|
194
|
+
titles=["Reference", "Reconstruction"],
|
|
195
|
+
color_palette="gray",
|
|
196
|
+
)
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### Overlay a segmentation
|
|
200
|
+
|
|
201
|
+
```python
|
|
202
|
+
from cmpl.visualization import visualize_segmentation_slice
|
|
203
|
+
|
|
204
|
+
visualize_segmentation_slice(
|
|
205
|
+
grayscale_image,
|
|
206
|
+
segmentation,
|
|
207
|
+
slice_number=20,
|
|
208
|
+
dimension="axial",
|
|
209
|
+
)
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## Quantitative MRI
|
|
213
|
+
|
|
214
|
+
Quantitative MRI functionality is available under:
|
|
215
|
+
|
|
216
|
+
```python
|
|
217
|
+
cmpl.qmr
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Install the PyTorch and visualization dependencies:
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
python -m pip install "cmpl[torch,viz]"
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### Reconstruct a multi-echo signal from T2* and S0 maps
|
|
227
|
+
|
|
228
|
+
```python
|
|
229
|
+
import numpy as np
|
|
230
|
+
|
|
231
|
+
from cmpl.quantitative_MRI import reconstruct_images
|
|
232
|
+
|
|
233
|
+
t2_star = np.full((64, 64, 8), 20.0, dtype=np.float32)
|
|
234
|
+
s0 = np.full((64, 64, 8), 100.0, dtype=np.float32)
|
|
235
|
+
echo_times = np.array([0.0, 5.0, 10.0, 15.0], dtype=np.float32)
|
|
236
|
+
|
|
237
|
+
images = reconstruct_images(
|
|
238
|
+
t2_star,
|
|
239
|
+
s0,
|
|
240
|
+
echo_times,
|
|
241
|
+
device="cpu",
|
|
242
|
+
return_numpy=True,
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
print(images.shape)
|
|
246
|
+
# (64, 64, 8, 4)
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
The signal model is:
|
|
250
|
+
|
|
251
|
+
```text
|
|
252
|
+
S(TE) = S0 * exp(-TE / T2*)
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### Fit a 3D two-parameter T2* model
|
|
256
|
+
|
|
257
|
+
```python
|
|
258
|
+
from cmpl.quantitative_MRI import t2_star_two_parametric_3D
|
|
259
|
+
|
|
260
|
+
result = t2_star_two_parametric_3D(
|
|
261
|
+
echo_times,
|
|
262
|
+
images,
|
|
263
|
+
num_iterations=1000,
|
|
264
|
+
initial_lr=0.01,
|
|
265
|
+
initial_T2_star=20.0,
|
|
266
|
+
plot_error=False,
|
|
267
|
+
device="cpu",
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
t2_star_map = result["T2_star_map"]
|
|
271
|
+
s0_map = result["S0_map"]
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
If CUDA is available and no device is supplied, the function can select a CUDA device automatically. CUDA usage will increase computation speed significantly.
|
|
275
|
+
|
|
276
|
+
### Calculate normalized fitting error
|
|
277
|
+
|
|
278
|
+
```python
|
|
279
|
+
from cmpl.quantitative_MRI import calculate_rmse_percentage_s0
|
|
280
|
+
|
|
281
|
+
rmse_pct, rse_pct = calculate_rmse_percentage_s0(
|
|
282
|
+
original_images,
|
|
283
|
+
reconstructed_images,
|
|
284
|
+
s0_map,
|
|
285
|
+
return_numpy=True,
|
|
286
|
+
)
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
CMPL also contains two- and three-parameter 2D/3D T2* fitting functions.
|
|
290
|
+
|
|
291
|
+
## Reconstruction
|
|
292
|
+
|
|
293
|
+
Reconstruction functionality is available under:
|
|
294
|
+
|
|
295
|
+
```python
|
|
296
|
+
cmpl.recon
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
PyTorch is required for the current reconstruction implementations:
|
|
300
|
+
|
|
301
|
+
```bash
|
|
302
|
+
python -m pip install "cmpl[torch]"
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### 1D GRAPPA
|
|
306
|
+
|
|
307
|
+
```python
|
|
308
|
+
from cmpl.reconstruction.grappa import grappa_1d_recon
|
|
309
|
+
|
|
310
|
+
reconstructed_kspace = grappa_1d_recon(
|
|
311
|
+
calibration_kspace,
|
|
312
|
+
undersampled_kspace,
|
|
313
|
+
reduction_factor=2,
|
|
314
|
+
kx=3,
|
|
315
|
+
ky=3,
|
|
316
|
+
)
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
`calibration_kspace` and `undersampled_kspace` are expected to contain coil-resolved k-space data. The current implementation uses the ordering:
|
|
320
|
+
|
|
321
|
+
```text
|
|
322
|
+
frequency, phase, slice, coils
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
### 2D GRAPPA
|
|
326
|
+
|
|
327
|
+
```python
|
|
328
|
+
from cmpl.reconstruction.grappa import grappa_2d_recon
|
|
329
|
+
|
|
330
|
+
reconstructed_kspace = grappa_2d_recon(
|
|
331
|
+
calibration_kspace,
|
|
332
|
+
undersampled_kspace,
|
|
333
|
+
kernel_size=(3, 3, 3),
|
|
334
|
+
reduction_factors=(2, 2),
|
|
335
|
+
)
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
### Conjugate-gradient SENSE
|
|
339
|
+
|
|
340
|
+
```python
|
|
341
|
+
from cmpl.reconstruction.sense import CG_sense_2D
|
|
342
|
+
|
|
343
|
+
reconstructed_image = CG_sense_2D(
|
|
344
|
+
undersampled_image_space,
|
|
345
|
+
coil_sensitivity,
|
|
346
|
+
)
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
Inputs to the current SENSE implementation are PyTorch tensors.
|
|
350
|
+
|
|
351
|
+
## I/O
|
|
352
|
+
|
|
353
|
+
Install the I/O extra:
|
|
354
|
+
|
|
355
|
+
```bash
|
|
356
|
+
python -m pip install "cmpl[io]"
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
### Read a NIfTI file
|
|
360
|
+
|
|
361
|
+
```python
|
|
362
|
+
from cmpl.utilities.io import nifti_read
|
|
363
|
+
|
|
364
|
+
nifti_image, data = nifti_read("image.nii.gz")
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
### Replace NIfTI data while preserving geometry
|
|
368
|
+
|
|
369
|
+
```python
|
|
370
|
+
from cmpl.utilities.io import update_nifti_data
|
|
371
|
+
|
|
372
|
+
updated = update_nifti_data(
|
|
373
|
+
"reference.nii.gz",
|
|
374
|
+
new_data,
|
|
375
|
+
output_path="updated.nii.gz",
|
|
376
|
+
)
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
### Load a DICOM directory
|
|
380
|
+
|
|
381
|
+
```python
|
|
382
|
+
from cmpl.utilities.io import load_dicom_scan_from_dir
|
|
383
|
+
|
|
384
|
+
volume = load_dicom_scan_from_dir(
|
|
385
|
+
"/path/to/dicom_directory",
|
|
386
|
+
reshape=True,
|
|
387
|
+
)
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
For multi-echo data, the loader can return data arranged as:
|
|
391
|
+
|
|
392
|
+
```text
|
|
393
|
+
x, y, z, echo
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
depending on the acquisition metadata and requested reshaping behavior.
|
|
397
|
+
|
|
398
|
+
### DICOM to SimpleITK
|
|
399
|
+
|
|
400
|
+
```python
|
|
401
|
+
from cmpl.utilities.io import dicom_to_SimpleITK
|
|
402
|
+
|
|
403
|
+
image = dicom_to_SimpleITK("/path/to/dicom_directory")
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
### Write a SimpleITK image as NIfTI
|
|
407
|
+
|
|
408
|
+
```python
|
|
409
|
+
from cmpl.utilities.io import itk_to_nifti
|
|
410
|
+
|
|
411
|
+
output_path = itk_to_nifti(
|
|
412
|
+
image,
|
|
413
|
+
"output.nii.gz",
|
|
414
|
+
)
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
### Enhanced-DICOM helpers
|
|
418
|
+
|
|
419
|
+
```python
|
|
420
|
+
from cmpl.dicom.enhanced_dicom import (
|
|
421
|
+
get_slice_thickness,
|
|
422
|
+
get_spacing_between_slices,
|
|
423
|
+
voxel_sizes_detailed,
|
|
424
|
+
)
|
|
425
|
+
|
|
426
|
+
details = voxel_sizes_detailed(dataset)
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
## Numerical utilities
|
|
430
|
+
|
|
431
|
+
Lightweight numerical helpers are kept separate from heavier I/O modules so visualization and other numerical workflows do not require unrelated optional dependencies.
|
|
432
|
+
|
|
433
|
+
```python
|
|
434
|
+
from cmpl.utilities.numerical import resize_matrix
|
|
435
|
+
|
|
436
|
+
resized = resize_matrix(
|
|
437
|
+
image,
|
|
438
|
+
target_shape=(600, 600),
|
|
439
|
+
)
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
`resize_matrix` accepts NumPy arrays and PyTorch tensors. PyTorch is imported at runtime only when a Torch tensor is actually passed to the function.
|
|
443
|
+
|
|
444
|
+
For backward compatibility, older imports such as:
|
|
445
|
+
|
|
446
|
+
```python
|
|
447
|
+
from cmpl.utilities.utils import resize_matrix
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
continue to work.
|
|
451
|
+
|
|
452
|
+
## Data indexing
|
|
453
|
+
|
|
454
|
+
Install the data extra:
|
|
455
|
+
|
|
456
|
+
```bash
|
|
457
|
+
python -m pip install "cmpl[data]"
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
CMPL includes a pandas-based utility for indexing a directory tree that follows the CMPL medical-data convention:
|
|
461
|
+
|
|
462
|
+
```python
|
|
463
|
+
from cmpl.utilities.df_build import build_medical_data_frame
|
|
464
|
+
|
|
465
|
+
df = build_medical_data_frame("/path/to/root")
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
The utility is designed around a structure such as:
|
|
469
|
+
|
|
470
|
+
```text
|
|
471
|
+
root/
|
|
472
|
+
├── Study001/
|
|
473
|
+
│ ├── Dicoms/
|
|
474
|
+
│ │ └── <contrast>/
|
|
475
|
+
│ ├── h5_files/
|
|
476
|
+
│ │ └── <contrast>.h5
|
|
477
|
+
│ └── Segmentations/
|
|
478
|
+
│ └── <contrast>/
|
|
479
|
+
│ └── <group>/
|
|
480
|
+
│ └── <segmentation>.nii.gz
|
|
481
|
+
└── Study002/
|
|
482
|
+
└── ...
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
This utility is convention-specific rather than a general filesystem indexer.
|
|
486
|
+
|
|
487
|
+
## Lazy loading and optional dependencies
|
|
488
|
+
|
|
489
|
+
CMPL is designed so that unrelated optional packages are not imported simply because the top-level package is imported.
|
|
490
|
+
|
|
491
|
+
For example:
|
|
492
|
+
|
|
493
|
+
```python
|
|
494
|
+
import cmpl
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
does not immediately require PyTorch, Matplotlib, pandas, nibabel, pydicom, SimpleITK, or h5py.
|
|
498
|
+
|
|
499
|
+
Optional functionality is loaded when its corresponding module or function is accessed. This keeps startup lightweight and allows users to install only the dependencies required for their workflow.
|
|
500
|
+
|
|
501
|
+
## Development
|
|
502
|
+
|
|
503
|
+
Clone the project and install it in editable mode with development dependencies:
|
|
504
|
+
|
|
505
|
+
```bash
|
|
506
|
+
python -m pip install -e ".[dev]"
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
For development across the currently tested major feature groups:
|
|
510
|
+
|
|
511
|
+
```bash
|
|
512
|
+
python -m pip install -e ".[dev,io,data,viz,torch]"
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
Run the test suite:
|
|
516
|
+
|
|
517
|
+
```bash
|
|
518
|
+
python -m pytest tests/ -v
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
The test suite includes:
|
|
522
|
+
|
|
523
|
+
- lazy-import and dependency-boundary tests
|
|
524
|
+
- qMRI numerical tests
|
|
525
|
+
- GRAPPA and SENSE reconstruction tests
|
|
526
|
+
- visualization smoke tests
|
|
527
|
+
- synthetic NIfTI, DICOM, and SimpleITK I/O tests
|
|
528
|
+
- data-indexing tests
|
|
529
|
+
|
|
530
|
+
### Build the package
|
|
531
|
+
|
|
532
|
+
```bash
|
|
533
|
+
python -m build
|
|
534
|
+
python -m twine check dist/*
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
## Package layout
|
|
538
|
+
|
|
539
|
+
```text
|
|
540
|
+
src/cmpl/
|
|
541
|
+
├── dicom/
|
|
542
|
+
│ └── enhanced_dicom.py
|
|
543
|
+
├── quantitative_MRI/
|
|
544
|
+
│ └── mapping.py
|
|
545
|
+
├── reconstruction/
|
|
546
|
+
│ ├── grappa/
|
|
547
|
+
│ │ ├── grappa_1D.py
|
|
548
|
+
│ │ ├── grappa_2D.py
|
|
549
|
+
│ │ └── utils.py
|
|
550
|
+
│ └── sense/
|
|
551
|
+
│ └── cg.py
|
|
552
|
+
├── utilities/
|
|
553
|
+
│ ├── df_build.py
|
|
554
|
+
│ ├── io.py
|
|
555
|
+
│ ├── numerical.py
|
|
556
|
+
│ └── utils.py
|
|
557
|
+
└── visualization/
|
|
558
|
+
└── visualization.py
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
## License
|
|
562
|
+
|
|
563
|
+
See the `LICENSE` file included with the project for licensing terms.
|
|
564
|
+
|
|
565
|
+
## Author
|
|
566
|
+
|
|
567
|
+
CMPL is developed by Eisa Hedayati at CMRR.
|