|
10 | 10 | import warnings
|
11 | 11 | import numpy as np
|
12 | 12 | from pathlib import Path
|
13 |
| -from scipy import ndimage as ndi |
14 | 13 |
|
15 |
| -from nibabel.loadsave import load as _nbload |
16 | 14 | from nibabel.affines import from_matvec
|
17 |
| -from nibabel.arrayproxy import get_obj_dtype |
18 | 15 |
|
19 | 16 | from nitransforms.base import (
|
20 | 17 | ImageGrid,
|
21 | 18 | TransformBase,
|
22 |
| - SpatialReference, |
23 | 19 | _as_homogeneous,
|
24 | 20 | EQUALITY_TOL,
|
25 | 21 | )
|
@@ -113,6 +109,10 @@ def __invert__(self):
|
113 | 109 | """
|
114 | 110 | return self.__class__(self._inverse)
|
115 | 111 |
|
| 112 | + def __len__(self): |
| 113 | + """Enable using len().""" |
| 114 | + return 1 if self._matrix.ndim == 2 else len(self._matrix) |
| 115 | + |
116 | 116 | def __matmul__(self, b):
|
117 | 117 | """
|
118 | 118 | Compose two Affines.
|
@@ -330,10 +330,6 @@ def __getitem__(self, i):
|
330 | 330 | """Enable indexed access to the series of matrices."""
|
331 | 331 | return Affine(self.matrix[i, ...], reference=self._reference)
|
332 | 332 |
|
333 |
| - def __len__(self): |
334 |
| - """Enable using len().""" |
335 |
| - return len(self._matrix) |
336 |
| - |
337 | 333 | def map(self, x, inverse=False):
|
338 | 334 | r"""
|
339 | 335 | Apply :math:`y = f(x)`.
|
@@ -402,119 +398,6 @@ def to_filename(self, filename, fmt="X5", moving=None):
|
402 | 398 | ).to_filename(filename)
|
403 | 399 | return filename
|
404 | 400 |
|
405 |
| - def apply( |
406 |
| - self, |
407 |
| - spatialimage, |
408 |
| - reference=None, |
409 |
| - order=3, |
410 |
| - mode="constant", |
411 |
| - cval=0.0, |
412 |
| - prefilter=True, |
413 |
| - output_dtype=None, |
414 |
| - ): |
415 |
| - """ |
416 |
| - Apply a transformation to an image, resampling on the reference spatial object. |
417 |
| -
|
418 |
| - Parameters |
419 |
| - ---------- |
420 |
| - spatialimage : `spatialimage` |
421 |
| - The image object containing the data to be resampled in reference |
422 |
| - space |
423 |
| - reference : spatial object, optional |
424 |
| - The image, surface, or combination thereof containing the coordinates |
425 |
| - of samples that will be sampled. |
426 |
| - order : int, optional |
427 |
| - The order of the spline interpolation, default is 3. |
428 |
| - The order has to be in the range 0-5. |
429 |
| - mode : {"constant", "reflect", "nearest", "mirror", "wrap"}, optional |
430 |
| - Determines how the input image is extended when the resamplings overflows |
431 |
| - a border. Default is "constant". |
432 |
| - cval : float, optional |
433 |
| - Constant value for ``mode="constant"``. Default is 0.0. |
434 |
| - prefilter: bool, optional |
435 |
| - Determines if the image's data array is prefiltered with |
436 |
| - a spline filter before interpolation. The default is ``True``, |
437 |
| - which will create a temporary *float64* array of filtered values |
438 |
| - if *order > 1*. If setting this to ``False``, the output will be |
439 |
| - slightly blurred if *order > 1*, unless the input is prefiltered, |
440 |
| - i.e. it is the result of calling the spline filter on the original |
441 |
| - input. |
442 |
| -
|
443 |
| - Returns |
444 |
| - ------- |
445 |
| - resampled : `spatialimage` or ndarray |
446 |
| - The data imaged after resampling to reference space. |
447 |
| -
|
448 |
| - """ |
449 |
| - |
450 |
| - if reference is not None and isinstance(reference, (str, Path)): |
451 |
| - reference = _nbload(str(reference)) |
452 |
| - |
453 |
| - _ref = ( |
454 |
| - self.reference if reference is None else SpatialReference.factory(reference) |
455 |
| - ) |
456 |
| - |
457 |
| - if isinstance(spatialimage, (str, Path)): |
458 |
| - spatialimage = _nbload(str(spatialimage)) |
459 |
| - |
460 |
| - # Avoid opening the data array just yet |
461 |
| - input_dtype = get_obj_dtype(spatialimage.dataobj) |
462 |
| - output_dtype = output_dtype or input_dtype |
463 |
| - |
464 |
| - # Prepare physical coordinates of input (grid, points) |
465 |
| - xcoords = _ref.ndcoords.astype("f4").T |
466 |
| - |
467 |
| - # Invert target's (moving) affine once |
468 |
| - ras2vox = ~Affine(spatialimage.affine) |
469 |
| - |
470 |
| - if spatialimage.ndim == 4 and (len(self) != spatialimage.shape[-1]): |
471 |
| - raise ValueError( |
472 |
| - "Attempting to apply %d transforms on a file with " |
473 |
| - "%d timepoints" % (len(self), spatialimage.shape[-1]) |
474 |
| - ) |
475 |
| - |
476 |
| - # Order F ensures individual volumes are contiguous in memory |
477 |
| - # Also matches NIfTI, making final save more efficient |
478 |
| - resampled = np.zeros( |
479 |
| - (xcoords.shape[0], len(self)), dtype=output_dtype, order="F" |
480 |
| - ) |
481 |
| - |
482 |
| - dataobj = ( |
483 |
| - np.asanyarray(spatialimage.dataobj, dtype=input_dtype) |
484 |
| - if spatialimage.ndim in (2, 3) |
485 |
| - else None |
486 |
| - ) |
487 |
| - |
488 |
| - for t, xfm_t in enumerate(self): |
489 |
| - # Map the input coordinates on to timepoint t of the target (moving) |
490 |
| - ycoords = xfm_t.map(xcoords)[..., : _ref.ndim] |
491 |
| - |
492 |
| - # Calculate corresponding voxel coordinates |
493 |
| - yvoxels = ras2vox.map(ycoords)[..., : _ref.ndim] |
494 |
| - |
495 |
| - # Interpolate |
496 |
| - resampled[..., t] = ndi.map_coordinates( |
497 |
| - ( |
498 |
| - dataobj |
499 |
| - if dataobj is not None |
500 |
| - else spatialimage.dataobj[..., t].astype(input_dtype, copy=False) |
501 |
| - ), |
502 |
| - yvoxels.T, |
503 |
| - output=output_dtype, |
504 |
| - order=order, |
505 |
| - mode=mode, |
506 |
| - cval=cval, |
507 |
| - prefilter=prefilter, |
508 |
| - ) |
509 |
| - |
510 |
| - if isinstance(_ref, ImageGrid): # If reference is grid, reshape |
511 |
| - newdata = resampled.reshape(_ref.shape + (len(self),)) |
512 |
| - moved = spatialimage.__class__(newdata, _ref.affine, spatialimage.header) |
513 |
| - moved.header.set_data_dtype(output_dtype) |
514 |
| - return moved |
515 |
| - |
516 |
| - return resampled |
517 |
| - |
518 | 401 |
|
519 | 402 | def load(filename, fmt=None, reference=None, moving=None):
|
520 | 403 | """
|
|
0 commit comments