Skip to content

Commit 5767039

Browse files
authored
Merge pull request #544 from oesteban/fix/542-rotate-to-cardinal
FIX: Segmentation plots aligned with cardinal axes
2 parents dbd2a97 + 8a6f088 commit 5767039

File tree

2 files changed

+34
-2
lines changed

2 files changed

+34
-2
lines changed

niworkflows/utils/images.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,27 @@
33
import numpy as np
44

55

6+
def rotation2canonical(img):
7+
"""Calculate the rotation w.r.t. cardinal axes of input image."""
8+
img = nb.as_closest_canonical(img)
9+
newaff = np.diag(img.header.get_zooms()[:3])
10+
r = newaff @ np.linalg.pinv(img.affine[:3, :3])
11+
if np.allclose(r, np.eye(3)):
12+
return None
13+
return r
14+
15+
16+
def rotate_affine(img, rot=None):
17+
"""Rewrite the affine of a spatial image."""
18+
if rot is None:
19+
return img
20+
21+
img = nb.as_closest_canonical(img)
22+
affine = np.eye(4)
23+
affine[:3] = rot @ img.affine[:3]
24+
return img.__class__(img.dataobj, affine, img.header)
25+
26+
627
def unsafe_write_nifti_header_and_data(fname, header, data):
728
"""Write header and data without any consistency checks or data munging
829

niworkflows/viz/utils.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
from nipype.utils import filemanip
2222
from .. import NIWORKFLOWS_LOG
23+
from ..utils.images import rotation2canonical, rotate_affine
2324

2425

2526
SVGNS = "http://www.w3.org/2000/svg"
@@ -216,19 +217,29 @@ def plot_segs(
216217
compress="auto",
217218
**plot_params
218219
):
219-
""" plot segmentation as contours over the image (e.g. anatomical).
220+
"""
221+
Generate a static mosaic with ROIs represented by their delimiting contour.
222+
223+
Plot segmentation as contours over the image (e.g. anatomical).
220224
seg_niis should be a list of files. mask_nii helps determine the cut
221225
coordinates. plot_params will be passed on to nilearn plot_* functions. If
222226
seg_niis is a list of size one, it behaves as if it was plotting the mask.
223227
"""
224228
plot_params = {} if plot_params is None else plot_params
225229

226230
image_nii = _3d_in_file(image_nii)
231+
canonical_r = rotation2canonical(image_nii)
232+
image_nii = rotate_affine(image_nii, rot=canonical_r)
233+
seg_niis = [rotate_affine(_3d_in_file(f), rot=canonical_r) for f in seg_niis]
227234
data = image_nii.get_fdata()
228235

229236
plot_params = robust_set_limits(data, plot_params)
230237

231-
bbox_nii = nb.load(image_nii if bbox_nii is None else bbox_nii)
238+
bbox_nii = (
239+
image_nii if bbox_nii is None
240+
else rotate_affine(_3d_in_file(bbox_nii), rot=canonical_r)
241+
)
242+
232243
if masked:
233244
bbox_nii = nlimage.threshold_img(bbox_nii, 1e-3)
234245

0 commit comments

Comments
 (0)