Skip to content

Commit 4380b9e

Browse files
committed
FIX: Segmentation plots aligned with cardinal axes
While nilearn/nilearn#25 is considered, this PR advances the generation of mosaics after aligning the affine matrix of the data with the cardinal axes. This should overcome the glitches when nilearn is requested to plot contours and the mask for the ROI has voxels that only partially intersect with the visualization plane. Resolves: #542. References: #281, #304. Depends: #543.
1 parent bb44cd7 commit 4380b9e

File tree

2 files changed

+22
-3
lines changed

2 files changed

+22
-3
lines changed

niworkflows/utils/images.py

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

55

6+
def as_canonical(img, hdr_ref=None):
7+
"""Drop rotation w.r.t. cardinal axes of input image."""
8+
img = nb.as_closest_canonical(img)
9+
zooms = list(img.header.get_zooms()[:3])
10+
newaff = np.diag(zooms + [1])
11+
rot = newaff[:3, :3].dot(np.linalg.inv(img.affine[:3, :3]))
12+
newaff[:3, 3] = rot.dot(img.affine[:3, 3])
13+
return nb.Nifti1Image(img.dataobj, newaff, img.header)
14+
15+
616
def unsafe_write_nifti_header_and_data(fname, header, data):
717
"""Write header and data without any consistency checks or data munging
818

niworkflows/viz/utils.py

Lines changed: 12 additions & 3 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 as_canonical
2324

2425

2526
SVGNS = "http://www.w3.org/2000/svg"
@@ -222,19 +223,27 @@ def plot_segs(
222223
compress="auto",
223224
**plot_params
224225
):
225-
""" plot segmentation as contours over the image (e.g. anatomical).
226+
"""
227+
Generate a static mosaic with ROIs represented by their delimiting contour.
228+
229+
Plot segmentation as contours over the image (e.g. anatomical).
226230
seg_niis should be a list of files. mask_nii helps determine the cut
227231
coordinates. plot_params will be passed on to nilearn plot_* functions. If
228232
seg_niis is a list of size one, it behaves as if it was plotting the mask.
229233
"""
230234
plot_params = {} if plot_params is None else plot_params
231235

232-
image_nii = _3d_in_file(image_nii)
236+
image_nii = as_canonical(_3d_in_file(image_nii))
237+
seg_niis = [as_canonical(_3d_in_file(f)) for f in seg_niis]
233238
data = image_nii.get_fdata()
234239

235240
plot_params = robust_set_limits(data, plot_params)
236241

237-
bbox_nii = nb.load(image_nii if bbox_nii is None else bbox_nii)
242+
bbox_nii = (
243+
image_nii if bbox_nii is None
244+
else as_canonical(_3d_in_file(bbox_nii))
245+
)
246+
238247
if masked:
239248
bbox_nii = nlimage.threshold_img(bbox_nii, 1e-3)
240249

0 commit comments

Comments
 (0)