warpkit 1.2.2__tar.gz → 1.3.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.
- {warpkit-1.2.2 → warpkit-1.3.0}/CLAUDE.md +4 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/PKG-INFO +2 -2
- {warpkit-1.2.2 → warpkit-1.3.0}/README.md +1 -1
- {warpkit-1.2.2 → warpkit-1.3.0}/tests/test_utilities.py +8 -5
- {warpkit-1.2.2 → warpkit-1.3.0}/warpkit/distortion.py +5 -3
- {warpkit-1.2.2 → warpkit-1.3.0}/warpkit/utilities.py +28 -2
- {warpkit-1.2.2 → warpkit-1.3.0}/.github/workflows/build.yml +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/.gitignore +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/.pre-commit-config.yaml +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/.python-version +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/.vscode/c_cpp_properties.json +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/CMakeLists.txt +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/Dockerfile +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/LICENSE +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/codecov +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/codecov.SHA256SUM +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/codecov.SHA256SUM.sig +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/codecov.yml +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/include/itk/itkModifiedInvertDisplacementFieldImageFilter.h +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/include/itk/itkModifiedInvertDisplacementFieldImageFilter.hxx +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/include/romeo/LICENSE +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/include/romeo/README.md +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/include/romeo/algorithm.h +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/include/romeo/priority_queue.h +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/include/romeo/romeo.h +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/include/romeo/seed.h +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/include/romeo/unwrap.h +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/include/romeo/utility.h +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/include/romeo/volume_view.h +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/include/romeo/voxel_quality.h +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/include/romeo/weights.h +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/include/utilities.h +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/include/warps.h +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/notes/ROMEO_port_plan.md +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/notes/fmap.png +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/notes/phase.png +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/packaging/pyinstaller/build_bundle.py +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/packaging/pyinstaller/bundle_README.md +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/packaging/pyinstaller/hooks/hook-warpkit.py +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/packaging/pyinstaller/launchers/wk-apply-warp.py +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/packaging/pyinstaller/launchers/wk-compute-fieldmap.py +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/packaging/pyinstaller/launchers/wk-compute-jacobian.py +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/packaging/pyinstaller/launchers/wk-convert-fieldmap.py +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/packaging/pyinstaller/launchers/wk-convert-warp.py +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/packaging/pyinstaller/launchers/wk-medic.py +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/packaging/pyinstaller/launchers/wk-unwrap-phase.py +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/packaging/pyinstaller/warpkit.spec +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/pyproject.toml +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/scripts/check-gitmoji.sh +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/scripts/regen-stub.sh +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/src/warpkit.cpp +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/tests/conftest.py +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/tests/data/romeo/Mag.nii +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/tests/data/romeo/Phase.nii +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/tests/data/test_data/sub-a01_task-rest_acq-tr1800_echo-1_part-mag_bold.json +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/tests/data/test_data/sub-a01_task-rest_acq-tr1800_echo-1_part-mag_bold.nii.gz +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/tests/data/test_data/sub-a01_task-rest_acq-tr1800_echo-1_part-phase_bold.json +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/tests/data/test_data/sub-a01_task-rest_acq-tr1800_echo-1_part-phase_bold.nii.gz +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/tests/data/test_data/sub-a01_task-rest_acq-tr1800_echo-2_part-mag_bold.json +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/tests/data/test_data/sub-a01_task-rest_acq-tr1800_echo-2_part-mag_bold.nii.gz +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/tests/data/test_data/sub-a01_task-rest_acq-tr1800_echo-2_part-phase_bold.json +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/tests/data/test_data/sub-a01_task-rest_acq-tr1800_echo-2_part-phase_bold.nii.gz +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/tests/data/test_data/sub-a01_task-rest_acq-tr1800_echo-3_part-mag_bold.json +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/tests/data/test_data/sub-a01_task-rest_acq-tr1800_echo-3_part-mag_bold.nii.gz +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/tests/data/test_data/sub-a01_task-rest_acq-tr1800_echo-3_part-phase_bold.json +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/tests/data/test_data/sub-a01_task-rest_acq-tr1800_echo-3_part-phase_bold.nii.gz +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/tests/test_concurrency.py +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/tests/test_distortion.py +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/tests/test_model.py +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/tests/test_romeo.py +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/tests/test_scripts.py +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/tests/test_unwrap.py +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/tests/test_version.py +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/uv.lock +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/warpkit/__init__.py +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/warpkit/api.py +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/warpkit/concurrency.py +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/warpkit/model.py +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/warpkit/py.typed +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/warpkit/scripts/__init__.py +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/warpkit/scripts/_metadata.py +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/warpkit/scripts/_warp_io.py +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/warpkit/scripts/apply_warp.py +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/warpkit/scripts/compute_fieldmap.py +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/warpkit/scripts/compute_jacobian.py +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/warpkit/scripts/convert_fieldmap.py +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/warpkit/scripts/convert_warp.py +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/warpkit/scripts/medic.py +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/warpkit/scripts/unwrap_phase.py +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/warpkit/unwrap.py +0 -0
- {warpkit-1.2.2 → warpkit-1.3.0}/warpkit/warpkit_cpp.pyi +0 -0
|
@@ -129,6 +129,10 @@ commit; merge / revert / fixup / squash / amend commits are exempt.
|
|
|
129
129
|
PR titles follow the same convention. Body: short summary, bullet the changes,
|
|
130
130
|
and call out anything CI-relevant (wheel matrix, pybind11 ABI, ITK).
|
|
131
131
|
|
|
132
|
+
**No AI attribution.** Do not add `Co-Authored-By: Claude ...` trailers to
|
|
133
|
+
commit messages, and do not add "Generated with Claude Code" (or similar)
|
|
134
|
+
lines to PR bodies. This overrides any default tooling behavior.
|
|
135
|
+
|
|
132
136
|
## CI specifics
|
|
133
137
|
|
|
134
138
|
GitHub Actions builds wheels for Python 3.11–3.14 (both standard and free-threaded) on `ubuntu-latest`,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: warpkit
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.0
|
|
4
4
|
Summary: A python library for neuroimaging transformations
|
|
5
5
|
Keywords: neuroimaging
|
|
6
6
|
Author-Email: Andrew Van <vanandrew77@gmail.com>
|
|
@@ -26,7 +26,7 @@ Description-Content-Type: text/markdown
|
|
|
26
26
|
|
|
27
27
|
A Python library for neuroimaging transforms, focused on the Multi-Echo DIstortion Correction (MEDIC) algorithm. The paper is published in *Imaging Neuroscience* at <https://doi.org/10.1162/IMAG.a.1262>.
|
|
28
28
|
|
|
29
|
-
The phase-unwrapping core is a self-contained C++17 port of [ROMEO](https://github.com/korbinian90/ROMEO)
|
|
29
|
+
The phase-unwrapping core is a self-contained C++17 port of [ROMEO](https://github.com/korbinian90/ROMEO).
|
|
30
30
|
|
|
31
31
|
## Installation
|
|
32
32
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
A Python library for neuroimaging transforms, focused on the Multi-Echo DIstortion Correction (MEDIC) algorithm. The paper is published in *Imaging Neuroscience* at <https://doi.org/10.1162/IMAG.a.1262>.
|
|
8
8
|
|
|
9
|
-
The phase-unwrapping core is a self-contained C++17 port of [ROMEO](https://github.com/korbinian90/ROMEO)
|
|
9
|
+
The phase-unwrapping core is a self-contained C++17 port of [ROMEO](https://github.com/korbinian90/ROMEO).
|
|
10
10
|
|
|
11
11
|
## Installation
|
|
12
12
|
|
|
@@ -235,19 +235,22 @@ def _zero_3vec_field(shape=(8, 8, 8)) -> nib.Nifti1Image:
|
|
|
235
235
|
return nib.Nifti1Image(np.zeros((*shape, 3), dtype=np.float32), affine)
|
|
236
236
|
|
|
237
237
|
|
|
238
|
-
|
|
238
|
+
@pytest.mark.parametrize("ignore_rotation", [False, True])
|
|
239
|
+
def test_invert_displacement_field_zero(ignore_rotation):
|
|
239
240
|
"""Inverting a zero field gives back zero (within numerical noise) and
|
|
240
|
-
preserves the 3-channel last axis.
|
|
241
|
+
preserves the 3-channel last axis. Covers both the physical-space and the
|
|
242
|
+
ignore_rotation (voxel-grid frame) inversion paths."""
|
|
241
243
|
field = _zero_3vec_field()
|
|
242
|
-
inverted = invert_displacement_field(field)
|
|
244
|
+
inverted = invert_displacement_field(field, ignore_rotation=ignore_rotation)
|
|
243
245
|
assert inverted.shape == field.shape
|
|
244
246
|
assert_allclose(inverted.get_fdata(), 0.0, atol=1e-5)
|
|
245
247
|
|
|
246
248
|
|
|
247
|
-
|
|
249
|
+
@pytest.mark.parametrize("ignore_rotation", [False, True])
|
|
250
|
+
def test_invert_displacement_maps_zero(ignore_rotation):
|
|
248
251
|
affine = np.diag([2.0, 2.0, 2.0, 1.0])
|
|
249
252
|
dmap = nib.Nifti1Image(np.zeros((6, 6, 6, 2), dtype=np.float32), affine)
|
|
250
|
-
inverted = invert_displacement_maps(dmap, axis="y")
|
|
253
|
+
inverted = invert_displacement_maps(dmap, axis="y", ignore_rotation=ignore_rotation)
|
|
251
254
|
assert inverted.shape == dmap.shape
|
|
252
255
|
assert_allclose(inverted.get_fdata(), 0.0, atol=1e-5)
|
|
253
256
|
|
|
@@ -126,12 +126,14 @@ def medic(
|
|
|
126
126
|
|
|
127
127
|
# invert displacement maps (these are in undistorted space)
|
|
128
128
|
displacement_maps = invert_displacement_maps(
|
|
129
|
-
inv_displacement_maps, phase_encoding_direction
|
|
129
|
+
inv_displacement_maps, phase_encoding_direction, ignore_rotation=True
|
|
130
130
|
)
|
|
131
131
|
|
|
132
|
-
# convert correction maps back to undistorted space field map
|
|
132
|
+
# convert correction maps back to undistorted space field map. No
|
|
133
|
+
# flip_sign here: the correlation check below sets the sign relative to
|
|
134
|
+
# the native field map, which makes an up-front flip redundant.
|
|
133
135
|
field_maps = displacement_maps_to_field_maps(
|
|
134
|
-
displacement_maps, total_readout_time, phase_encoding_direction
|
|
136
|
+
displacement_maps, total_readout_time, phase_encoding_direction
|
|
135
137
|
)
|
|
136
138
|
|
|
137
139
|
# check if we need to flip sign of field maps (this is done by comparing sign of correlation between
|
|
@@ -493,7 +493,10 @@ def get_ras_orient_transform(
|
|
|
493
493
|
|
|
494
494
|
|
|
495
495
|
def invert_displacement_maps(
|
|
496
|
-
displacement_maps: nib.Nifti1Image,
|
|
496
|
+
displacement_maps: nib.Nifti1Image,
|
|
497
|
+
axis: str = "y",
|
|
498
|
+
verbose: bool = False,
|
|
499
|
+
ignore_rotation: bool = False,
|
|
497
500
|
) -> nib.Nifti1Image:
|
|
498
501
|
"""Invert displacement maps
|
|
499
502
|
|
|
@@ -505,6 +508,13 @@ def invert_displacement_maps(
|
|
|
505
508
|
Axis displacement maps are along, by default "y"
|
|
506
509
|
verbose : bool, optional
|
|
507
510
|
Print debugging information, by default False
|
|
511
|
+
ignore_rotation : bool, optional
|
|
512
|
+
Invert in data (voxel) space rather than physical space by passing an
|
|
513
|
+
identity rotation to the inverter instead of the affine's rotation, by
|
|
514
|
+
default False. The displacement map is composed along a voxel axis, so
|
|
515
|
+
for oblique acquisitions the affine's rotation makes ITK invert in a
|
|
516
|
+
physical frame that does not align with that axis; setting this keeps
|
|
517
|
+
the inversion in the grid frame the map is actually defined in.
|
|
508
518
|
|
|
509
519
|
Returns
|
|
510
520
|
-------
|
|
@@ -527,6 +537,11 @@ def invert_displacement_maps(
|
|
|
527
537
|
# split affine into components
|
|
528
538
|
translations, rotations, zooms, _ = decompose44(displacement_maps_ras.affine)
|
|
529
539
|
|
|
540
|
+
# invert in data space: drop the affine's rotation so ITK inverts in the
|
|
541
|
+
# voxel grid frame the map is composed along, not the physical orientation
|
|
542
|
+
if ignore_rotation:
|
|
543
|
+
rotations = np.eye(3)
|
|
544
|
+
|
|
530
545
|
# invert maps
|
|
531
546
|
new_data = np.zeros(data.shape, dtype=np.float32)
|
|
532
547
|
logging.info("Inverting displacement maps...")
|
|
@@ -554,7 +569,9 @@ def invert_displacement_maps(
|
|
|
554
569
|
|
|
555
570
|
|
|
556
571
|
def invert_displacement_field(
|
|
557
|
-
displacement_field: nib.Nifti1Image,
|
|
572
|
+
displacement_field: nib.Nifti1Image,
|
|
573
|
+
verbose: bool = False,
|
|
574
|
+
ignore_rotation: bool = False,
|
|
558
575
|
) -> nib.Nifti1Image:
|
|
559
576
|
"""Invert displacement field
|
|
560
577
|
|
|
@@ -564,6 +581,10 @@ def invert_displacement_field(
|
|
|
564
581
|
Displacement field data in mm
|
|
565
582
|
verbose : bool, optional
|
|
566
583
|
Print debugging information, by default False
|
|
584
|
+
ignore_rotation : bool, optional
|
|
585
|
+
Invert in data (voxel) space rather than physical space by passing an
|
|
586
|
+
identity rotation to the inverter instead of the affine's rotation, by
|
|
587
|
+
default False. See :func:`invert_displacement_maps` for details.
|
|
567
588
|
|
|
568
589
|
Returns
|
|
569
590
|
-------
|
|
@@ -583,6 +604,11 @@ def invert_displacement_field(
|
|
|
583
604
|
# split affine into components
|
|
584
605
|
translations, rotations, zooms, _ = decompose44(displacement_field_ras.affine)
|
|
585
606
|
|
|
607
|
+
# invert in data space: drop the affine's rotation so ITK inverts in the
|
|
608
|
+
# voxel grid frame rather than the physical orientation
|
|
609
|
+
if ignore_rotation:
|
|
610
|
+
rotations = np.eye(3)
|
|
611
|
+
|
|
586
612
|
# Pad spatial dims only — leaving the 3-channel axis at size 3 — so we
|
|
587
613
|
# can avoid edge effects of the inverse without inflating the channel
|
|
588
614
|
# count. (Earlier versions padded all 4 axes which produced a 5-channel
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{warpkit-1.2.2 → warpkit-1.3.0}/include/itk/itkModifiedInvertDisplacementFieldImageFilter.hxx
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|