Skip to content

[FIX] Improve bounding box computation from masks #304

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

Merged
merged 6 commits into from
Feb 7, 2019

Conversation

oesteban
Copy link
Member

@oesteban oesteban commented Feb 7, 2019

Before (fieldmap of ds054 on fmriprep's reports at Circle):
before
After:
after

@oesteban oesteban requested a review from effigies February 7, 2019 00:08
Copy link
Member

@effigies effigies left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The result looks good, but honestly I have no idea how you made it happen. Could you add some comments explaining the process a little bit?

int((mask_data.shape[1] * mask_data.shape[2]) * 0.2), # sagittal
int((mask_data.shape[0] * mask_data.shape[2]) * 0.0), # coronal
int((mask_data.shape[0] * mask_data.shape[1]) * 0.3), # axial
]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is opaque to me. ijk_th reads like threshold, but I don't see how this should produce a threshold.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added some comments 👍

@oesteban
Copy link
Member Author

oesteban commented Feb 7, 2019

This patch still does not address the real underlying problem (it would involve resampling the mask into an affine that is aligned with the canonical axes) but it does the job.

@oesteban
Copy link
Member Author

oesteban commented Feb 7, 2019

@effigies, please let me know if I managed to clarify the idea with the comments. If so, feel free to merge.

Copy link
Member

@effigies effigies left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So my primary concern with this is what happens with small or degenerate masks? Do we have tests that show what this looks like for various masks?

ras_coords.append(apply_affine(mask_nii.affine, cross).tolist())

ras_coords.append(apply_affine(
mask_nii.affine, cross).tolist())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible that the problem is actually just that we don't make sure these are integers, being sure to round up at the bottom and down at the top?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nilearn takes physical coordinates, so I doubt this is the problem.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, but if we round the physical coordinates to outside the mask, then we might get undefined behavior. We certainly get something.

Copy link
Member Author

@oesteban oesteban Feb 7, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A warning saying that no contours were found was thrown. Nilearn used to not plot anything in that case, but after some release the weird contours would show up. The thresholds solution should take care of most of the cases where this rounding happened, as we don't compute the bounding box of the mask, but the bounding box of the mask with a decent amount of masked pixels instead. The tests were failing with very small masks, but 55aa451 should fix that falling back to the old calculation (with your suggestion in #304 (comment)).

That said, the issue I'm afraid, is that nilearn rotates the images (and the masks) to align with canonical axes in visualization. As the brain is not perfectly spherical, these rotations might force the coordinates outside the brain if you calculate them exactly at the brain surface (as we were doing) for very tilted brains.

I think that this implementation will basically satisfy 99.9% of the cases and the remaining 0.1% will have the weird contours - which are confusing but not harmful.

mask_data = mask_nii.get_data()
B = np.argwhere(mask_data > 0)
start_coords = B.min(0)
stop_coords = B.max(0) + 1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or maybe this should have just been stop_coords = B.max(0)?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This indeed seemingly fixed the issue (that was the first thing I tried). However, being at it, I wanted to improve the visualization because such a liberal calculation usually gave almost empty views of the axial plane in many images.

@oesteban
Copy link
Member Author

oesteban commented Feb 7, 2019

Reports are looking good - thumbs up?

@oesteban oesteban merged commit 7d50907 into nipreps:master Feb 7, 2019
@oesteban oesteban deleted the fix/281-contours branch February 7, 2019 20:23
oesteban added a commit to oesteban/niworkflows that referenced this pull request Jun 20, 2020
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: nipreps#542.
References: nipreps#281, nipreps#304.
Depends: nipreps#543.
oesteban added a commit to oesteban/niworkflows that referenced this pull request Jun 20, 2020
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: nipreps#542.
References: nipreps#281, nipreps#304.
Depends: nipreps#543.
oesteban added a commit to oesteban/niworkflows that referenced this pull request Jun 20, 2020
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: nipreps#542.
References: nipreps#281, nipreps#304.
Depends: nipreps#543.
oesteban added a commit to oesteban/niworkflows that referenced this pull request Jun 23, 2020
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: nipreps#542.
References: nipreps#281, nipreps#304.
Depends: nipreps#543.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants