|
10 | 10 | """
|
11 | 11 | from __future__ import division, print_function
|
12 | 12 |
|
| 13 | +from os.path import dirname, join as pjoin |
| 14 | + |
13 | 15 | import numpy as np
|
14 | 16 | import numpy.linalg as npl
|
15 | 17 |
|
16 |
| -from ..optpkg import optional_package |
| 18 | +from nibabel.optpkg import optional_package |
17 | 19 | spnd, have_scipy, _ = optional_package('scipy.ndimage')
|
18 | 20 |
|
19 |
| -from ..processing import (sigma2fwhm, fwhm2sigma, adapt_affine, |
20 |
| - resample_from_to, resample_to_output, smooth_image) |
21 |
| -from ..nifti1 import Nifti1Image |
22 |
| -from ..nifti2 import Nifti2Image |
23 |
| -from ..orientations import flip_axis, inv_ornt_aff |
24 |
| -from ..affines import AffineError, from_matvec, to_matvec |
25 |
| -from ..eulerangles import euler2mat |
| 21 | +import nibabel as nib |
| 22 | +from nibabel.processing import (sigma2fwhm, fwhm2sigma, adapt_affine, |
| 23 | + resample_from_to, resample_to_output, smooth_image) |
| 24 | +from nibabel.nifti1 import Nifti1Image |
| 25 | +from nibabel.nifti2 import Nifti2Image |
| 26 | +from nibabel.orientations import flip_axis, inv_ornt_aff |
| 27 | +from nibabel.affines import AffineError, from_matvec, to_matvec, apply_affine |
| 28 | +from nibabel.eulerangles import euler2mat |
26 | 29 |
|
27 | 30 | from numpy.testing import (assert_almost_equal,
|
28 | 31 | assert_array_equal)
|
|
31 | 34 | from nose.tools import (assert_true, assert_false, assert_raises,
|
32 | 35 | assert_equal, assert_not_equal)
|
33 | 36 |
|
34 |
| -from .test_spaces import assert_all_in, get_outspace_params |
| 37 | +from nibabel.tests.test_spaces import assert_all_in, get_outspace_params |
| 38 | +from nibabel.testing import assert_allclose_safely |
35 | 39 |
|
36 | 40 | needs_scipy = skipif(not have_scipy, 'These tests need scipy')
|
37 | 41 |
|
| 42 | +DATA_DIR = pjoin(dirname(__file__), 'data') |
38 | 43 |
|
39 | 44 | def test_sigma2fwhm():
|
40 | 45 | # Test from constant
|
@@ -339,3 +344,55 @@ def test_smooth_image():
|
339 | 344 | assert_equal(
|
340 | 345 | smooth_image(img_ni2, 0, out_class=None).__class__,
|
341 | 346 | Nifti2Image)
|
| 347 | + |
| 348 | + |
| 349 | +def assert_spm_resampling_close(from_img, our_resampled, spm_resampled): |
| 350 | + """ Assert our resampling is close to SPM's, allowing for edge effects |
| 351 | + """ |
| 352 | + # To allow for differences in the way SPM and scipy.ndimage handle off-edge |
| 353 | + # interpolation, mask out voxels off edge |
| 354 | + to_img_shape = spm_resampled.shape |
| 355 | + to_img_affine = spm_resampled.affine |
| 356 | + to_vox_coords = np.indices(to_img_shape).transpose((1, 2, 3, 0)) |
| 357 | + # Coordinates of to_img mapped to from_img |
| 358 | + to_to_from = npl.inv(from_img.affine).dot(to_img_affine) |
| 359 | + resamp_coords = apply_affine(to_to_from, to_vox_coords) |
| 360 | + # Places where SPM may not return default value but scipy.ndimage will (SPM |
| 361 | + # does not return zeros <0.05 from image edges). |
| 362 | + # See: https://github.com/nipy/nibabel/pull/255#issuecomment-186774173 |
| 363 | + outside_vol = np.any((resamp_coords < 0) | |
| 364 | + (np.subtract(resamp_coords, from_img.shape) > -1), |
| 365 | + axis=-1) |
| 366 | + spm_res = np.where(outside_vol, np.nan, np.array(spm_resampled.dataobj)) |
| 367 | + assert_allclose_safely(our_resampled.dataobj, spm_res) |
| 368 | + assert_almost_equal(our_resampled.affine, spm_resampled.affine, 5) |
| 369 | + |
| 370 | + |
| 371 | +@needs_scipy |
| 372 | +def test_against_spm_resample(): |
| 373 | + # Test resampling against images resampled with SPM12 |
| 374 | + # anatomical.nii has a diagonal -2, 2 2 affine; |
| 375 | + # functional.nii has a diagonal -4, 4 4 affine; |
| 376 | + # These are a bit boring, so first add some rotations and translations to |
| 377 | + # the anatomical image affine, and then resample to the first volume in the |
| 378 | + # functional, and compare to the same thing in SPM. |
| 379 | + # See ``make_moved_anat.py`` script in this directory for input to SPM. |
| 380 | + anat = nib.load(pjoin(DATA_DIR, 'anatomical.nii')) |
| 381 | + func = nib.load(pjoin(DATA_DIR, 'functional.nii')) |
| 382 | + some_rotations = euler2mat(0.1, 0.2, 0.3) |
| 383 | + extra_affine = from_matvec(some_rotations, [3, 4, 5]) |
| 384 | + moved_anat = nib.Nifti1Image(anat.get_data().astype(float), |
| 385 | + extra_affine.dot(anat.affine), |
| 386 | + anat.header) |
| 387 | + one_func = nib.Nifti1Image(func.dataobj[..., 0], |
| 388 | + func.affine, |
| 389 | + func.header) |
| 390 | + moved2func = resample_from_to(moved_anat, one_func, order=1, cval=np.nan) |
| 391 | + spm_moved = nib.load(pjoin(DATA_DIR, 'resampled_anat_moved.nii')) |
| 392 | + assert_spm_resampling_close(moved_anat, moved2func, spm_moved) |
| 393 | + # Next we resample the rotated anatomical image to output space, and compare |
| 394 | + # to the same operation done with SPM (our own version of 'reorient.m' by |
| 395 | + # John Ashburner). |
| 396 | + moved2output = resample_to_output(moved_anat, 4, order=1, cval=np.nan) |
| 397 | + spm2output = nib.load(pjoin(DATA_DIR, 'reoriented_anat_moved.nii')) |
| 398 | + assert_spm_resampling_close(moved_anat, moved2output, spm2output); |
0 commit comments