Skip to content

Commit ac5cd21

Browse files
MarcCoteeffigies
andcommitted
Add inplace option to apply_affine.
Co-authored-by: Chris Markiewicz <[email protected]>
1 parent 4703f4d commit ac5cd21

File tree

2 files changed

+23
-4
lines changed

2 files changed

+23
-4
lines changed

nibabel/affines.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class AffineError(ValueError):
1414
pass
1515

1616

17-
def apply_affine(aff, pts):
17+
def apply_affine(aff, pts, inplace=False):
1818
""" Apply affine matrix `aff` to points `pts`
1919
2020
Returns result of application of `aff` to the *right* of `pts`. The
@@ -39,6 +39,9 @@ def apply_affine(aff, pts):
3939
pts : (..., N-1) array-like
4040
Points, where the last dimension contains the coordinates of each
4141
point. For 3D, the last dimension will be length 3.
42+
inplace : bool, optional
43+
If False, the affine operation is done on a copy of `pts`.
44+
Otherwise, `pts` gets modified directly.
4245
4346
Returns
4447
-------
@@ -80,8 +83,18 @@ def apply_affine(aff, pts):
8083
# rzs == rotations, zooms, shears
8184
rzs = aff[:-1, :-1]
8285
trans = aff[:-1, -1]
83-
res = np.dot(pts, rzs.T) + trans[None, :]
84-
return res.reshape(shape)
86+
87+
if inplace:
88+
try:
89+
np.dot(pts, rzs.T, out=pts)
90+
except ValueError:
91+
inplace = False
92+
else:
93+
pts += trans[None, :]
94+
if not inplace:
95+
pts = pts @ rzs.T + trans[None, :]
96+
97+
return pts.reshape(shape)
8598

8699

87100
def to_matvec(transform):

nibabel/tests/test_affines.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@ def test_apply_affine():
5555
pts = pts.reshape((2, 2, 3))
5656
exp_res = exp_res.reshape((2, 2, 3))
5757
assert_array_equal(apply_affine(aff, pts), exp_res)
58+
59+
# Check inplace modification.
60+
res = apply_affine(aff, pts, inplace=True)
61+
assert_array_equal(res, exp_res)
62+
assert np.shares_memory(res, pts)
63+
5864
# That ND also works
5965
for N in range(2, 6):
6066
aff = np.eye(N)
@@ -203,7 +209,7 @@ def test_rescale_affine():
203209
orig_zooms = voxel_sizes(orig_aff)
204210
orig_axcodes = aff2axcodes(orig_aff)
205211
orig_centroid = apply_affine(orig_aff, (orig_shape - 1) // 2)
206-
212+
207213
for new_shape in (None, tuple(orig_shape), (256, 256, 256), (64, 64, 40)):
208214
for new_zooms in ((1, 1, 1), (2, 2, 3), (0.5, 0.5, 0.5)):
209215
new_aff = rescale_affine(orig_aff, orig_shape, new_zooms, new_shape)

0 commit comments

Comments
 (0)