cmpl 0.2.2__tar.gz → 0.2.3__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.
Files changed (44) hide show
  1. {cmpl-0.2.2/src/cmpl.egg-info → cmpl-0.2.3}/PKG-INFO +234 -134
  2. {cmpl-0.2.2 → cmpl-0.2.3}/README.md +234 -134
  3. {cmpl-0.2.2 → cmpl-0.2.3}/pyproject.toml +3 -1
  4. cmpl-0.2.3/src/cmpl/cli/__init__.py +3 -0
  5. cmpl-0.2.3/src/cmpl/cli/dicom_to_nifti.py +113 -0
  6. {cmpl-0.2.2 → cmpl-0.2.3}/src/cmpl/dicom/enhanced_dicom.py +205 -0
  7. {cmpl-0.2.2 → cmpl-0.2.3}/src/cmpl/utilities/io.py +745 -23
  8. {cmpl-0.2.2 → cmpl-0.2.3/src/cmpl.egg-info}/PKG-INFO +234 -134
  9. {cmpl-0.2.2 → cmpl-0.2.3}/src/cmpl.egg-info/SOURCES.txt +3 -0
  10. cmpl-0.2.3/src/cmpl.egg-info/entry_points.txt +2 -0
  11. {cmpl-0.2.2 → cmpl-0.2.3}/LICENSE +0 -0
  12. {cmpl-0.2.2 → cmpl-0.2.3}/setup.cfg +0 -0
  13. {cmpl-0.2.2 → cmpl-0.2.3}/src/cmpl/__init__.py +0 -0
  14. {cmpl-0.2.2 → cmpl-0.2.3}/src/cmpl/_version.py +0 -0
  15. {cmpl-0.2.2 → cmpl-0.2.3}/src/cmpl/dicom/__init__.py +0 -0
  16. {cmpl-0.2.2 → cmpl-0.2.3}/src/cmpl/dicom/geometry.py +0 -0
  17. {cmpl-0.2.2 → cmpl-0.2.3}/src/cmpl/dicom/metadata.py +0 -0
  18. {cmpl-0.2.2 → cmpl-0.2.3}/src/cmpl/quantitative_MRI/__init__.py +0 -0
  19. {cmpl-0.2.2 → cmpl-0.2.3}/src/cmpl/quantitative_MRI/mapping.py +0 -0
  20. {cmpl-0.2.2 → cmpl-0.2.3}/src/cmpl/reconstruction/__init__.py +0 -0
  21. {cmpl-0.2.2 → cmpl-0.2.3}/src/cmpl/reconstruction/grappa/__init__.py +0 -0
  22. {cmpl-0.2.2 → cmpl-0.2.3}/src/cmpl/reconstruction/grappa/grappa_1D.py +0 -0
  23. {cmpl-0.2.2 → cmpl-0.2.3}/src/cmpl/reconstruction/grappa/grappa_2D.py +0 -0
  24. {cmpl-0.2.2 → cmpl-0.2.3}/src/cmpl/reconstruction/grappa/utils.py +0 -0
  25. {cmpl-0.2.2 → cmpl-0.2.3}/src/cmpl/reconstruction/sense/__init__.py +0 -0
  26. {cmpl-0.2.2 → cmpl-0.2.3}/src/cmpl/reconstruction/sense/cg.py +0 -0
  27. {cmpl-0.2.2 → cmpl-0.2.3}/src/cmpl/segmentation/MRISegmentationTool.py +0 -0
  28. {cmpl-0.2.2 → cmpl-0.2.3}/src/cmpl/segmentation/__init__.py +0 -0
  29. {cmpl-0.2.2 → cmpl-0.2.3}/src/cmpl/segmentation/tools.py +0 -0
  30. {cmpl-0.2.2 → cmpl-0.2.3}/src/cmpl/utilities/__init__.py +0 -0
  31. {cmpl-0.2.2 → cmpl-0.2.3}/src/cmpl/utilities/df_build.py +0 -0
  32. {cmpl-0.2.2 → cmpl-0.2.3}/src/cmpl/utilities/numerical.py +0 -0
  33. {cmpl-0.2.2 → cmpl-0.2.3}/src/cmpl/utilities/utils.py +0 -0
  34. {cmpl-0.2.2 → cmpl-0.2.3}/src/cmpl/visualization/__init__.py +0 -0
  35. {cmpl-0.2.2 → cmpl-0.2.3}/src/cmpl/visualization/visualization.py +0 -0
  36. {cmpl-0.2.2 → cmpl-0.2.3}/src/cmpl.egg-info/dependency_links.txt +0 -0
  37. {cmpl-0.2.2 → cmpl-0.2.3}/src/cmpl.egg-info/requires.txt +0 -0
  38. {cmpl-0.2.2 → cmpl-0.2.3}/src/cmpl.egg-info/top_level.txt +0 -0
  39. {cmpl-0.2.2 → cmpl-0.2.3}/tests/test_data.py +0 -0
  40. {cmpl-0.2.2 → cmpl-0.2.3}/tests/test_installation.py +0 -0
  41. {cmpl-0.2.2 → cmpl-0.2.3}/tests/test_io.py +0 -0
  42. {cmpl-0.2.2 → cmpl-0.2.3}/tests/test_qmr.py +0 -0
  43. {cmpl-0.2.2 → cmpl-0.2.3}/tests/test_reconstruction.py +0 -0
  44. {cmpl-0.2.2 → cmpl-0.2.3}/tests/test_visualization.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cmpl
3
- Version: 0.2.2
3
+ Version: 0.2.3
4
4
  Summary: CMRR MRI Processing Libraries
5
5
  Author: Eisa Hedayati
6
6
  License: Copyright (c) 2025 Eisa Hedayati
@@ -71,23 +71,31 @@ Dynamic: license-file
71
71
 
72
72
  # CMPL — CMRR MRI Processing Libraries
73
73
 
74
- [![PyPI](https://img.shields.io/pypi/v/cmpl.svg)](https://pypi.org/project/cmpl/)
75
- [![Python](https://img.shields.io/pypi/pyversions/cmpl.svg)](https://pypi.org/project/cmpl/)
74
+ [![PyPI version](https://img.shields.io/pypi/v/cmpl.svg)](https://pypi.org/project/cmpl/)
75
+ [![Python versions](https://img.shields.io/pypi/pyversions/cmpl.svg)](https://pypi.org/project/cmpl/)
76
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.
77
+ PyPI: https://pypi.org/project/cmpl/
78
+
79
+ GitHub: https://github.com/ehedayati/cmpl
80
+
81
+ CMPL is a Python package for MRI processing workflows developed at CMRR. It provides tools for MRI reconstruction, quantitative MRI, visualization, DICOM/NIfTI conversion and I/O, and supporting numerical and data utilities.
78
82
 
79
83
  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
84
 
81
85
  ## Highlights
82
86
 
87
+ - Direct, geometry-aware conventional and Enhanced DICOM to NIfTI conversion with JSON metadata sidecars
88
+ - Multi-echo DICOM support, including 4D NIfTI output ordered by echo time
89
+ - Packaged `cmpl-dicom-to-nifti` command-line converter
90
+ - DICOM geometry and acquisition-metadata utilities
83
91
  - Parallel MRI reconstruction with 1D/2D GRAPPA and conjugate-gradient SENSE
84
92
  - 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
93
+ - MRI visualization utilities for 2D comparisons and 3D volume browsing
94
+ - Conventional and Enhanced DICOM, NIfTI, HDF5, and SimpleITK utilities
87
95
  - Lightweight numerical utilities shared across CMPL
88
96
  - Optional pandas-based indexing for CMPL-style medical-data directory structures
89
97
  - 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`
98
+ - Convenient aliases such as `cmpl.recon`, `cmpl.qmr`, `cmpl.vis`, and `cmpl.io`
91
99
 
92
100
  ## Requirements
93
101
 
@@ -149,144 +157,192 @@ CMPL exposes convenient aliases for commonly used subpackages:
149
157
  cmpl.recon # reconstruction
150
158
  cmpl.qmr # quantitative MRI
151
159
  cmpl.vis # visualization
152
- cmpl.utils # utilities
153
160
  cmpl.io # I/O utilities
161
+ cmpl.dicom # DICOM metadata and geometry utilities
162
+ cmpl.utils # utilities
154
163
  ```
155
164
 
156
165
  The aliases are resolved lazily, so importing CMPL itself does not require every optional dependency to be loaded.
157
166
 
158
- ## Visualization
167
+ ## DICOM and NIfTI I/O
159
168
 
160
- Install the visualization extra:
169
+ Install the I/O extra:
161
170
 
162
171
  ```bash
163
- python -m pip install "cmpl[viz]"
172
+ python -m pip install "cmpl[io]"
164
173
  ```
165
174
 
166
- ### Browse or display a 3D MRI volume
175
+ ### Convert a DICOM series directly to NIfTI
176
+
177
+ CMPL includes direct DICOM-series to NIfTI conversion for both conventional and Enhanced DICOM. The converter detects the DICOM representation automatically, preserves spatial geometry, supports single- and multi-echo acquisitions, writes the NIfTI image, and creates a matching JSON sidecar containing acquisition metadata and source geometry.
167
178
 
168
179
  ```python
169
- from cmpl.visualization import plot_3D_mri
180
+ import cmpl
170
181
 
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,
182
+ metadata = cmpl.io.dicom_to_nifti(
183
+ "/path/to/dicom_series",
184
+ "output.nii.gz",
180
185
  )
181
186
  ```
182
187
 
183
- If an interactive Matplotlib backend is available, `plot_3D_mri` can use interactive controls. Otherwise it falls back to static redraw mode.
188
+ This creates:
184
189
 
190
+ ```text
191
+ output.nii.gz
192
+ output.json
193
+ ```
185
194
 
186
- ### Compare images side by side
195
+ If the output path does not end in `.nii` or `.nii.gz`, CMPL appends `.nii.gz` automatically.
187
196
 
188
- ```python
189
- from cmpl.visualization import side_by_side_view
197
+ For a single echo, the output is a 3D image. When multiple echoes are present, CMPL groups volumes by DICOM `EchoTime`, orders them by echo time, and writes a 4D NIfTI image.
190
198
 
191
- side_by_side_view(
192
- image_a,
193
- image_b,
194
- titles=["Reference", "Reconstruction"],
195
- color_palette="gray",
199
+ The JSON sidecar includes:
200
+
201
+ - selected acquisition metadata
202
+ - echo time or echo times in milliseconds
203
+ - original DICOM slice-plane geometry in LPS coordinates
204
+ - the SimpleITK image size, origin, spacing, and direction used for conversion
205
+
206
+ The returned value is the same metadata dictionary written to the JSON sidecar.
207
+
208
+ If a directory contains multiple DICOM series, a specific `SeriesInstanceUID` can be selected:
209
+
210
+ ```python
211
+ metadata = cmpl.io.dicom_to_nifti(
212
+ "/path/to/dicom_directory",
213
+ "output.nii.gz",
214
+ series_id="1.2.840...",
196
215
  )
197
216
  ```
198
217
 
199
- ### Overlay a segmentation
218
+ ### Command-line DICOM conversion
200
219
 
201
- ```python
202
- from cmpl.visualization import visualize_segmentation_slice
220
+ Installing the I/O extra also installs the `cmpl-dicom-to-nifti` command:
203
221
 
204
- visualize_segmentation_slice(
205
- grayscale_image,
206
- segmentation,
207
- slice_number=20,
208
- dimension="axial",
209
- )
222
+ ```bash
223
+ python -m pip install "cmpl[io]"
210
224
  ```
211
225
 
212
- ## Quantitative MRI
226
+ Convert a DICOM series with automatic conventional/Enhanced-DICOM detection:
213
227
 
214
- Quantitative MRI functionality is available under:
228
+ ```bash
229
+ cmpl-dicom-to-nifti /path/to/dicom_series
230
+ ```
215
231
 
216
- ```python
217
- cmpl.qmr
232
+ The same CLI can also be invoked as a Python module:
233
+
234
+ ```bash
235
+ python -m cmpl.cli.dicom_to_nifti /path/to/dicom_series
218
236
  ```
219
237
 
220
- Install the PyTorch and visualization dependencies:
238
+ If the output path is omitted, CMPL writes the NIfTI image and JSON sidecar to the current directory using the DICOM directory name:
239
+
240
+ ```text
241
+ ./<series_directory_name>.nii.gz
242
+ ./<series_directory_name>.json
243
+ ```
244
+
245
+ An explicit output path can also be supplied:
221
246
 
222
247
  ```bash
223
- python -m pip install "cmpl[torch,viz]"
248
+ cmpl-dicom-to-nifti \
249
+ /path/to/dicom_series \
250
+ /path/to/output.nii.gz
224
251
  ```
225
252
 
226
- ### Reconstruct a multi-echo signal from T2* and S0 maps
253
+ Progress output is enabled by default. Disable it with:
254
+
255
+ ```bash
256
+ cmpl-dicom-to-nifti /path/to/dicom_series --no-verbose
257
+ ```
258
+
259
+ The same CLI handles conventional single-frame DICOM series and Enhanced multi-frame DICOM series. For multi-echo data, echo volumes are ordered by EchoTime and written as a 4D NIfTI image.
260
+
261
+ ### Read a NIfTI file
227
262
 
228
263
  ```python
229
- import numpy as np
264
+ from cmpl.utilities.io import nifti_read
230
265
 
231
- from cmpl.quantitative_MRI import reconstruct_images
266
+ nifti_image, data = nifti_read("image.nii.gz")
267
+ ```
232
268
 
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)
269
+ ### Replace NIfTI data while preserving geometry
236
270
 
237
- images = reconstruct_images(
238
- t2_star,
239
- s0,
240
- echo_times,
241
- device="cpu",
242
- return_numpy=True,
271
+ ```python
272
+ from cmpl.utilities.io import update_nifti_data
273
+
274
+ updated = update_nifti_data(
275
+ "reference.nii.gz",
276
+ new_data,
277
+ output_path="updated.nii.gz",
243
278
  )
279
+ ```
244
280
 
245
- print(images.shape)
246
- # (64, 64, 8, 4)
281
+ ### Load a DICOM directory as a NumPy array
282
+
283
+ ```python
284
+ from cmpl.utilities.io import load_dicom_scan_from_dir
285
+
286
+ volume = load_dicom_scan_from_dir(
287
+ "/path/to/dicom_directory",
288
+ reshape=True,
289
+ )
247
290
  ```
248
291
 
249
- The signal model is:
292
+ For multi-echo data, the loader can return data arranged as:
250
293
 
251
294
  ```text
252
- S(TE) = S0 * exp(-TE / T2*)
295
+ x, y, z, echo
253
296
  ```
254
297
 
255
- ### Fit a 3D two-parameter T2* model
298
+ depending on the acquisition metadata and requested reshaping behavior.
256
299
 
257
- ```python
258
- from cmpl.quantitative_MRI import t2_star_two_parametric_3D
300
+ ### Read a DICOM series as SimpleITK
259
301
 
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
- )
302
+ ```python
303
+ from cmpl.utilities.io import dicom_to_SimpleITK
269
304
 
270
- t2_star_map = result["T2_star_map"]
271
- s0_map = result["S0_map"]
305
+ image = dicom_to_SimpleITK("/path/to/dicom_directory")
272
306
  ```
273
307
 
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.
308
+ The returned image is 3D for a single echo and 4D when multiple echoes are detected.
275
309
 
276
- ### Calculate normalized fitting error
310
+ ### Write a SimpleITK image as NIfTI
277
311
 
278
312
  ```python
279
- from cmpl.quantitative_MRI import calculate_rmse_percentage_s0
313
+ from cmpl.utilities.io import itk_to_nifti
280
314
 
281
- rmse_pct, rse_pct = calculate_rmse_percentage_s0(
282
- original_images,
283
- reconstructed_images,
284
- s0_map,
285
- return_numpy=True,
315
+ output_path = itk_to_nifti(
316
+ image,
317
+ "output.nii.gz",
286
318
  )
287
319
  ```
288
320
 
289
- CMPL also contains two- and three-parameter 2D/3D T2* fitting functions.
321
+ ### DICOM geometry and metadata helpers
322
+
323
+ CMPL separates DICOM geometry and acquisition-metadata handling into dedicated modules under `cmpl.dicom`.
324
+
325
+ ```python
326
+ from cmpl.dicom import (
327
+ extract_slice_geometry,
328
+ get_slice_position,
329
+ )
330
+
331
+ geometry = extract_slice_geometry("slice001.dcm")
332
+ position = get_slice_position("slice001.dcm")
333
+ ```
334
+
335
+ Enhanced-DICOM helpers remain available as well:
336
+
337
+ ```python
338
+ from cmpl.dicom.enhanced_dicom import (
339
+ get_slice_thickness,
340
+ get_spacing_between_slices,
341
+ voxel_sizes_detailed,
342
+ )
343
+
344
+ details = voxel_sizes_detailed(dataset)
345
+ ```
290
346
 
291
347
  ## Reconstruction
292
348
 
@@ -338,7 +394,7 @@ reconstructed_kspace = grappa_2d_recon(
338
394
  ### Conjugate-gradient SENSE
339
395
 
340
396
  ```python
341
- from cmpl.reconstruction.sense import CG_sense_2D
397
+ from cmpl.reconstruction.sense.cg import CG_sense_2D
342
398
 
343
399
  reconstructed_image = CG_sense_2D(
344
400
  undersampled_image_space,
@@ -348,82 +404,123 @@ reconstructed_image = CG_sense_2D(
348
404
 
349
405
  Inputs to the current SENSE implementation are PyTorch tensors.
350
406
 
351
- ## I/O
407
+ ## Quantitative MRI
352
408
 
353
- Install the I/O extra:
409
+ Quantitative MRI functionality is available under:
354
410
 
355
- ```bash
356
- python -m pip install "cmpl[io]"
411
+ ```python
412
+ cmpl.qmr
357
413
  ```
358
414
 
359
- ### Read a NIfTI file
360
-
361
- ```python
362
- from cmpl.utilities.io import nifti_read
415
+ Install the PyTorch and visualization dependencies:
363
416
 
364
- nifti_image, data = nifti_read("image.nii.gz")
417
+ ```bash
418
+ python -m pip install "cmpl[torch,viz]"
365
419
  ```
366
420
 
367
- ### Replace NIfTI data while preserving geometry
421
+ ### Reconstruct a multi-echo signal from T2* and S0 maps
368
422
 
369
423
  ```python
370
- from cmpl.utilities.io import update_nifti_data
424
+ import numpy as np
371
425
 
372
- updated = update_nifti_data(
373
- "reference.nii.gz",
374
- new_data,
375
- output_path="updated.nii.gz",
426
+ from cmpl.quantitative_MRI import reconstruct_images
427
+
428
+ t2_star = np.full((64, 64, 8), 20.0, dtype=np.float32)
429
+ s0 = np.full((64, 64, 8), 100.0, dtype=np.float32)
430
+ echo_times = np.array([0.0, 5.0, 10.0, 15.0], dtype=np.float32)
431
+
432
+ images = reconstruct_images(
433
+ t2_star,
434
+ s0,
435
+ echo_times,
436
+ device="cpu",
437
+ return_numpy=True,
376
438
  )
439
+
440
+ print(images.shape)
441
+ # (64, 64, 8, 4)
442
+ ```
443
+
444
+ The signal model is:
445
+
446
+ ```text
447
+ S(TE) = S0 * exp(-TE / T2*)
377
448
  ```
378
449
 
379
- ### Load a DICOM directory
450
+ ### Fit a 3D two-parameter T2* model
380
451
 
381
452
  ```python
382
- from cmpl.utilities.io import load_dicom_scan_from_dir
453
+ from cmpl.quantitative_MRI import t2_star_two_parametric_3D
383
454
 
384
- volume = load_dicom_scan_from_dir(
385
- "/path/to/dicom_directory",
386
- reshape=True,
455
+ result = t2_star_two_parametric_3D(
456
+ echo_times,
457
+ images,
458
+ num_iterations=1000,
459
+ initial_lr=0.01,
460
+ initial_T2_star=20.0,
461
+ plot_error=False,
462
+ device="cpu",
387
463
  )
464
+
465
+ t2_star_map = result["T2_star_map"]
466
+ s0_map = result["S0_map"]
388
467
  ```
389
468
 
390
- For multi-echo data, the loader can return data arranged as:
469
+ If CUDA is available and no device is supplied, the function can select a CUDA device automatically. CUDA usage can significantly accelerate fitting.
391
470
 
392
- ```text
393
- x, y, z, echo
471
+ ### Calculate normalized fitting error
472
+
473
+ ```python
474
+ from cmpl.quantitative_MRI import calculate_rmse_percentage_s0
475
+
476
+ rmse_pct, rse_pct = calculate_rmse_percentage_s0(
477
+ original_images,
478
+ reconstructed_images,
479
+ s0_map,
480
+ return_numpy=True,
481
+ )
394
482
  ```
395
483
 
396
- depending on the acquisition metadata and requested reshaping behavior.
484
+ CMPL also contains two- and three-parameter 2D/3D T2* fitting functions.
397
485
 
398
- ### DICOM to SimpleITK
486
+ ## Visualization
399
487
 
400
- ```python
401
- from cmpl.utilities.io import dicom_to_SimpleITK
488
+ Install the visualization extra:
402
489
 
403
- image = dicom_to_SimpleITK("/path/to/dicom_directory")
490
+ ```bash
491
+ python -m pip install "cmpl[viz]"
404
492
  ```
405
493
 
406
- ### Write a SimpleITK image as NIfTI
494
+ ### Browse or display a 3D MRI volume
407
495
 
408
496
  ```python
409
- from cmpl.utilities.io import itk_to_nifti
497
+ from cmpl.visualization import plot_3D_mri
410
498
 
411
- output_path = itk_to_nifti(
412
- image,
413
- "output.nii.gz",
499
+ plot_3D_mri(
500
+ volume,
501
+ slice_number=volume.shape[2] // 2,
502
+ alpha=0.5,
503
+ direction="sagittal",
504
+ cmap="gray",
505
+ vmin=0,
506
+ vmax=1,
507
+ dpi=300,
414
508
  )
415
509
  ```
416
510
 
417
- ### Enhanced-DICOM helpers
511
+ If an interactive Matplotlib backend is available, `plot_3D_mri` can use interactive controls. Otherwise it falls back to static redraw mode.
512
+
513
+ ### Compare images side by side
418
514
 
419
515
  ```python
420
- from cmpl.dicom.enhanced_dicom import (
421
- get_slice_thickness,
422
- get_spacing_between_slices,
423
- voxel_sizes_detailed,
424
- )
516
+ from cmpl.visualization import side_by_side_view
425
517
 
426
- details = voxel_sizes_detailed(dataset)
518
+ side_by_side_view(
519
+ image_a,
520
+ image_b,
521
+ titles=["Reference", "Reconstruction"],
522
+ color_palette="gray",
523
+ )
427
524
  ```
428
525
 
429
526
  ## Numerical utilities
@@ -472,12 +569,8 @@ root/
472
569
  ├── Study001/
473
570
  │ ├── Dicoms/
474
571
  │ │ └── <contrast>/
475
- │ ├── h5_files/
476
- │ │ └── <contrast>.h5
477
- │ └── Segmentations/
478
- │ └── <contrast>/
479
- │ └── <group>/
480
- │ └── <segmentation>.nii.gz
572
+ │ └── h5_files/
573
+ │ └── <contrast>.h5
481
574
  └── Study002/
482
575
  └── ...
483
576
  ```
@@ -494,7 +587,7 @@ For example:
494
587
  import cmpl
495
588
  ```
496
589
 
497
- does not immediately require PyTorch, Matplotlib, pandas, nibabel, pydicom, SimpleITK, or h5py.
590
+ does not immediately import PyTorch, Matplotlib, pandas, nibabel, pydicom, SimpleITK, h5py, or the Jupyter visualization stack.
498
591
 
499
592
  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
593
 
@@ -525,6 +618,8 @@ The test suite includes:
525
618
  - GRAPPA and SENSE reconstruction tests
526
619
  - visualization smoke tests
527
620
  - synthetic NIfTI, DICOM, and SimpleITK I/O tests
621
+ - conventional and Enhanced multi-echo DICOM-to-NIfTI conversion and JSON-sidecar tests
622
+ - DICOM geometry and metadata tests
528
623
  - data-indexing tests
529
624
 
530
625
  ### Build the package
@@ -538,8 +633,13 @@ python -m twine check dist/*
538
633
 
539
634
  ```text
540
635
  src/cmpl/
636
+ ├── _version.py
637
+ ├── cli/
638
+ │ └── dicom_to_nifti.py
541
639
  ├── dicom/
542
- │ └── enhanced_dicom.py
640
+ │ ├── enhanced_dicom.py
641
+ │ ├── geometry.py
642
+ │ └── metadata.py
543
643
  ├── quantitative_MRI/
544
644
  │ └── mapping.py
545
645
  ├── reconstruction/