-
Notifications
You must be signed in to change notification settings - Fork 577
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Rendering problems with add_contours when binary images have rotations set in the affine matrix #2537
Comments
Thx for sharing the problem ! |
In the example that I attached, that would be here: add_contours() calls |
I had a look at this today and I was able to reproduce the issue with the code and data you provided @vnckppl import numpy as np
import matplotlib.pyplot as plt
from nilearn import plotting
from nilearn.image import load_img, get_data
ddir = '/home/nicolas/Downloads/contour_issue/contour_issue/data'
# File names
template_default = ddir + '/SUIT.nii.gz'
template_rotated = ddir + '/SUIT_rot.nii.gz'
binROI_default = ddir + '/suitROI.nii.gz'
binROI_rotated = ddir + '/suitROI_rot.nii.gz'
# Load files
td = load_img(template_default)
tr = load_img(template_rotated)
rd = load_img(binROI_default)
rr = load_img(binROI_rotated)
# Check the data
assert np.all(td.affine == rd.affine)
assert np.all(tr.affine == rr.affine)
assert np.all(get_data(td) == get_data(tr))
assert np.all(get_data(rd) == get_data(rr))
assert np.all(np.unique(get_data(rd)) == [0,1])
assert np.all(np.unique(get_data(rr)) == [0,1])
# Plot td with rd contours
display = plotting.plot_anat(td)
display.add_contours(rd, colors="#00ff00")
# Plot tr with rr contours with same cut for comparison
display = plotting.plot_anat(tr, cut_coords = (-1,-36,-24))
display.add_contours(rr, colors="#00ff00") After investigation, I believe the problem comes indeed from the function nilearn/nilearn/plotting/displays.py Line 753 in 0c6388a
nilearn/nilearn/plotting/displays.py Line 780 in 0c6388a
isn't correct anymore which results in the weird looking output. As a fix, I propose to call if type not in ('contour', 'contourf'):
img = reorder_img(img, resample=resampling_interpolation) If you add this fix and re-run the code above, you should get the following output: |
Hmmm... After looking more into this I realize that my previous message and the proposed fix are wrong. I believe the problem comes from the fact that, since the affine is not considered diagonal in the code below, the binary image is resampled with continuous interpolation: nilearn/nilearn/image/resampling.py Lines 694 to 706 in bb3cd50
|
So the solution would be to turn to nearest interpolation for binary images ? Actually, what makes more sense would be to interpolate the image from which the edges are estimated, and not interpolate an image (possibly raise a warning if this is done)... |
The problem is happening here: nilearn/nilearn/image/resampling.py Lines 270 to 275 in bb3cd50
Before this line
This is indeed a possible solution. For example, doing something like this: def _map_show(self, img, type='imshow',
resampling_interpolation='continuous',
threshold=None, **kwargs):
# This function would move somewhere more appropriate...
def _is_binary_image(img):
img = load_img(img)
data = _utils.niimg._safe_get_data(img, ensure_finite=True)
unique_values = np.unique(data)
if len(unique_values) != 2:
return False
return sorted(list(unique_values)) == [0,1]
if _is_binary_image(img):
img = reorder_img(img, resample='nearest')
else:
img = reorder_img(img, resample=resampling_interpolation)
threshold = float(threshold) if threshold is not None else None
.... gives this output with the example code of my first message:
I'm not sure I understand what you mean here. In the code above, the resampling operation is applied to both |
My point is that to avoid surprises, you should avoid reinterpolating a binary image. Since the binary image is always obtained from another initial image, I'd resample this original image rather than the binary (edge) image. |
So please go ahead with this solution. thx ! |
The problem
When I plot a binary image that has some rotation to it in the affine header using Nilearn's
add_contours
function, the resulting image includes many additional lines that are not part of the surface of the ROI in the binary image. I don't encounter these issues when I use the same code with the same image that has not rotation set in the affine matrix.Reproduction of the issue
I have attached example data and code to reproduce this problem:
contour_issue.zip
My environment
Python 3.8.3 (default, May 27 2020, 20:53:40)
matplotlib==3.2.2
nilearn==0.6.2
The text was updated successfully, but these errors were encountered: