def test_compose():
    value = np.array([[1.0, 2.0, 3.0]]).T
    aa = compose(E.a, E.a)
    yield assert_true, aa.inverse() is None
    yield assert_true, np.allclose(aa(value), 4 * value)
    ab = compose(E.a, E.b)
    yield assert_true, ab.inverse() is None
    assert_true, np.allclose(ab(value), 4 * value)
    ac = compose(E.a, E.c)
    yield assert_true, ac.inverse() is None
    yield assert_true, np.allclose(ac(value), value)
    bb = compose(E.b, E.b)
    #    yield assert_true, bb.inverse() is not None
    aff1 = np.diag([1, 2, 3, 1])
    affine1 = AffineTransform.from_params("ijk", "xyz", aff1)
    aff2 = np.diag([4, 5, 6, 1])
    affine2 = AffineTransform.from_params("xyz", "abc", aff2)
    # compose mapping from 'ijk' to 'abc'
    compcm = compose(affine2, affine1)
    yield assert_equal, compcm.function_domain.coord_names, ("i", "j", "k")
    yield assert_equal, compcm.function_range.coord_names, ("a", "b", "c")
    yield assert_equal, compcm.affine, np.dot(aff2, aff1)
    # check invalid coordinate mappings
    yield assert_raises, ValueError, compose, affine1, affine2

    yield assert_raises, ValueError, compose, affine1, "foo"

    cm1 = CoordinateMap(CoordinateSystem("ijk"), CoordinateSystem("xyz"), np.log)
    cm2 = CoordinateMap(CoordinateSystem("xyz"), CoordinateSystem("abc"), np.exp)
    yield assert_raises, ValueError, compose, cm1, cm2
def test_compose():
    value = np.array([[1., 2., 3.]]).T
    aa = compose(E.a, E.a)
    yield assert_true, aa.inverse() is None
    yield assert_true, np.allclose(aa(value), 4*value)
    ab = compose(E.a,E.b)
    yield assert_true, ab.inverse() is None
    assert_true, np.allclose(ab(value), 4*value)
    ac = compose(E.a,E.c)
    yield assert_true, ac.inverse() is None
    yield assert_true, np.allclose(ac(value), value)
    bb = compose(E.b,E.b)
    #    yield assert_true, bb.inverse() is not None
    aff1 = np.diag([1,2,3,1])
    affine1 = AffineTransform.from_params('ijk', 'xyz', aff1)
    aff2 = np.diag([4,5,6,1])
    affine2 = AffineTransform.from_params('xyz', 'abc', aff2)
    # compose mapping from 'ijk' to 'abc'
    compcm = compose(affine2, affine1)
    yield assert_equal, compcm.function_domain.coord_names, ('i', 'j', 'k')
    yield assert_equal, compcm.function_range.coord_names, ('a', 'b', 'c')
    yield assert_equal, compcm.affine, np.dot(aff2, aff1)
    # check invalid coordinate mappings
    yield assert_raises, ValueError, compose, affine1, affine2

    yield assert_raises, ValueError, compose, affine1, 'foo'

    cm1 = CoordinateMap(CoordinateSystem('ijk'),
                        CoordinateSystem('xyz'), np.log)
    cm2 = CoordinateMap(CoordinateSystem('xyz'),
                        CoordinateSystem('abc'), np.exp)
    yield assert_raises, ValueError, compose, cm1, cm2
def test_inverse1():
    inv = lambda a: a.inverse()
    yield assert_true, inv(E.a) is None
    yield assert_true, inv(E.c) is None
    inv_b = E.b.inverse()
    inv_d = E.d.inverse()
    ident_b = compose(inv_b,E.b)
    ident_d = compose(inv_d,E.d)
    value = np.array([[1., 2., 3.]]).T
    yield assert_true, np.allclose(ident_b(value), value)
    yield assert_true, np.allclose(ident_d(value), value)
Beispiel #4
0
def change_basis(element, bchange_linear):
    """
    Matrices can be thought of as representations of linear mappings
    between two (coordinate-free) vector spaces represented in
    particular bases.

    Hence, a MatrixGroup instance with matrix.shape = (ndim, ndim)
    represents a linear transformation L on a vector space of
    dimension ndim, in a given coordinate system.

    If we change the basis in which we represent L, 
    the matrix that represents L should also change. 

    A change of basis is represented as a mapping between two
    coordinate systems and is also represented by a change of basis
    matrix.  This is expressed in this function as
    bchange_linear.output_coords == element.coords
    
    This function expresses the same transformation L in a different
    basis.

    """

    newcm = compose(bchange_linear.inverse, element, bchange_linear)
    matrix = newcm.affine[:-1,:-1]
    if bchange_linear.output_coords != element.coords:
        raise ValueError('expecting the basis change mapping to have the same output coords as element')
    return element.__class__(matrix, newcm.input_coords)
Beispiel #5
0
def change_basis(element, bchange_linear):
    """
    Matrices can be thought of as representations of linear mappings
    between two (coordinate-free) vector spaces represented in
    particular bases.

    Hence, a MatrixGroup instance with matrix.shape = (ndim, ndim)
    represents a linear transformation L on a vector space of
    dimension ndim, in a given coordinate system.

    If we change the basis in which we represent L, 
    the matrix that represents L should also change. 

    A change of basis is represented as a mapping between two
    coordinate systems and is also represented by a change of basis
    matrix.  This is expressed in this function as
    bchange_linear.function_range == element.coords
    
    This function expresses the same transformation L in a different
    basis.

    """

    newcm = compose(bchange_linear.inverse(), element, bchange_linear)
    matrix = newcm.affine[:-1, :-1]
    if bchange_linear.function_range != element.coords:
        raise ValueError(
            'expecting the basis change mapping to have the same output coords as element'
        )
    return element.__class__(matrix, newcm.function_domain)
Beispiel #6
0
def product(*elements):
    """
    Compute the group product of a set of elements
    """
    notsame = filter(lambda x: type(x) != type(elements[0]), elements)
    if notsame:
        raise ValueError('all elements should be members of the same group')
    composed_mapping = compose(*elements)
    matrix = composed_mapping.affine[:-1,:-1]
    return elements[0].__class__(matrix, elements[0].coords)
Beispiel #7
0
def product(*elements):
    """
    Compute the group product of a set of elements
    """
    notsame = filter(lambda x: type(x) != type(elements[0]), elements)
    if notsame:
        raise ValueError('all elements should be members of the same group')
    composed_mapping = compose(*elements)
    matrix = composed_mapping.affine[:-1, :-1]
    return elements[0].__class__(matrix, elements[0].coords)
Beispiel #8
0
def product(*elements):
    """
    Compute the group product of a set of elements
    """
    type_e0 = type(elements[0])
    notsame = [e for e in elements if not type(e) == type_e0]
    if notsame:
        raise ValueError('all elements should be members of the same group')
    composed_mapping = compose(*elements)
    matrix = composed_mapping.affine[:-1, :-1]
    return elements[0].__class__(matrix, elements[0].coords)
Beispiel #9
0
def product(*elements):
    """
    Compute the group product of a set of elements
    """
    type_e0 = type(elements[0])
    notsame = [e for e in elements if not type(e) == type_e0]
    if notsame:
        raise ValueError('all elements should be members of the same group')
    composed_mapping = compose(*elements)
    matrix = composed_mapping.affine[:-1,:-1]
    return elements[0].__class__(matrix, elements[0].coords)
Beispiel #10
0
 def to_ni_image(self, t, f, grid_shape=None, prior_mask=None):
     """Form a NIPY Image of the map of this object at (t,f). The new
     Image will have a CoordinateMap transforming the array indices into
     the target space of this Beam's coregistered MRI.
     """
     print 'slicing tf beam at t,f =', (t,f)
     if (prior_mask is not None) and (prior_mask.shape == self.s.shape):
         prior_mask = prior_mask[:,t,f]
     m_arr = signal_array_to_masked_vol(self.s[:,t,f], self.voxel_indices,
                                        grid_shape=grid_shape,
                                        prior_mask=prior_mask)
     meg2mri = self.coreg.meg2mri
     return ni_api.Image(m_arr, compose(meg2mri, self.coordmap))
Beispiel #11
0
def test_compose():
    value = np.array([[1., 2., 3.]]).T
    aa = compose(E.a, E.a)
    yield assert_true, aa.inverse is None
    yield assert_true, np.allclose(aa(value), 4*value)
    ab = compose(E.a,E.b)
    yield assert_true, ab.inverse is None
    assert_true, np.allclose(ab(value), 4*value)
    ac = compose(E.a,E.c)
    yield assert_true, ac.inverse is None
    yield assert_true, np.allclose(ac(value), value)
    bb = compose(E.b,E.b)
    yield assert_true, bb.inverse is not None
    aff1 = np.diag([1,2,3,1])
    cm1 = Affine.from_params('ijk', 'xyz', aff1)
    aff2 = np.diag([4,5,6,1])
    cm2 = Affine.from_params('xyz', 'abc', aff2)
    # compose mapping from 'ijk' to 'abc'
    compcm = compose(cm2, cm1)
    yield assert_equal, compcm.input_coords.coord_names, ('i', 'j', 'k')
    yield assert_equal, compcm.output_coords.coord_names, ('a', 'b', 'c')
    yield assert_equal, compcm.affine, np.dot(aff2, aff1)
    # check invalid coordinate mappings
    yield assert_raises, ValueError, compose, cm1, cm2
Beispiel #12
0
def test_subsample():

    # This is how you would subsample with nipy.algorithms.resample
    # On the first axis, we'll take every 2nd,
    # on the second axis every 3rd, and on the 3rd every 4th

    im, xyz_im, ras = generate_im()

    subsample_matrix = np.array([[2,0,0,0],
                                 [0,3,0,0],
                                 [0,0,4,0],
                                 [0,0,0,1]])
                                
    subsampled_shape = np.array(xyz_im)[::2,::3,::4].shape
    subsample_coordmap = AffineTransform(xyz_im.xyz_transform.function_domain,
                                         xyz_im.xyz_transform.function_domain,
                                         subsample_matrix)
    target_coordmap = compose(xyz_im.xyz_transform, 
                              subsample_coordmap)

    # The images have the same output coordinates

    world_to_world_coordmap = AffineTransform(xyz_im.xyz_transform.function_range,
                                              xyz_im.xyz_transform.function_range,
                                              np.identity(4))

    im_subsampled = resample(xyz_im, target_coordmap,
                             world_to_world_coordmap,
                             shape=subsampled_shape)
    xyz_im_subsampled = xyz_image.XYZImage(np.array(im_subsampled),
                                           im_subsampled.affine,
                                           im_subsampled.coordmap.function_domain.coord_names)

    yield assert_almost_equal, np.array(xyz_im_subsampled), np.array(xyz_im)[::2,::3,::4]

    # We can now do subsampling with these methods.
    xyz_im_subsampled2 = xyz_im.resampled_to_affine(target_coordmap, 
                                                         shape=subsampled_shape)
    yield assert_almost_equal, np.array(xyz_im_subsampled2), np.array(xyz_im_subsampled)
    yield assert_true, xyz_im_subsampled2 == xyz_im_subsampled
Beispiel #13
0
    def from_image(klass, image, axis=0):

        # Now, reorder the axes and reference

        image = rollaxis(image, axis)

        imlist = []
        coordmap = image.coordmap

        # We drop the first output coordinate of image's coordmap

        drop1st = np.identity(coordmap.ndims[1]+1)[1:]
        drop1st_domain = image.reference
        drop1st_range = CoordinateSystem(image.reference.coord_names[1:],
                                 name=image.reference.name,
                                 coord_dtype=image.reference.coord_dtype)
        drop1st_coordmap = AffineTransform(drop1st_domain, drop1st_range,
                                           drop1st)

        # And arbitrarily add a 0 for the first axis

        add0 = np.vstack([np.zeros(image.axes.ndim),
                          np.identity(image.axes.ndim)])
        add0_domain = CoordinateSystem(image.axes.coord_names[1:],
                                 name=image.axes.name,
                                 coord_dtype=image.axes.coord_dtype)
        add0_range = image.axes
        add0_coordmap = AffineTransform(add0_domain, add0_range,
                                        add0)

        coordmap = compose(drop1st_coordmap, image.coordmap, add0_coordmap)
                                         
        data = np.asarray(image)
        imlist = [Image(dataslice, copy(coordmap))
                  for dataslice in data]
        return klass(imlist)
def test_compose_cmap():
    value = np.array([1., 2., 3.])
    b = compose(E.e, E.e)
    assert_true(np.allclose(b(value), value))
Beispiel #15
0
def ni_affine_pixdim_from_affine(affine_transform, strict=False):
    """

    Given a square affine_transform,
    return a new 3-dimensional AffineTransform
    and the pixel dimensions in dimensions 
    greater than 3.

    If strict is True, then an exception is raised if
    the affine matrix is not diagonal with
    positive entries in dimensions 
    greater than 3. 

    If strict is True, then the names of the range coordinates
    must be LPS:('x+LR','y+PA','z+SI') or RAS:('x+RL','y+AP','z+SI'). If strict is False, and the names
    are not either of these, LPS:('x+LR','y+PA','z+SI') are used.

    If the names are RAS:('x+RL','y+AA','z+SI'), then the affine is flipped
    so the result is in LPS:('x+LR','y+PA','z+SI').

    NIFTI images have the first 3 dimensions as spatial, and the
    remaining as non-spatial, with the 4th typically being time.

    Parameters
    ----------
    affine_transform : `AffineTransform`

    Returns
    -------
    nifti_transform: `AffineTransform`
       A 3-dimensional or less AffineTransform

    pixdim : ndarray(np.float)
       The pixel dimensions greater than 3.

    >>> outnames = CS(('x+LR','y+PA','z+SI') + ('t',))
    >>> innames = CS(['phase', 'j', 'frequency', 't'])
    >>> af_tr = AT(outnames, innames, np.diag([2,-2,3,3.5,1]))
    >>> print af_tr
    AffineTransform(
       function_domain=CoordinateSystem(coord_names=('x+LR', 'y+PA', 'z+SI', 't'), name='', coord_dtype=float64),
       function_range=CoordinateSystem(coord_names=('phase', 'j', 'frequency', 't'), name='', coord_dtype=float64),
       affine=array([[ 2. ,  0. ,  0. ,  0. ,  0. ],
                     [ 0. , -2. ,  0. ,  0. ,  0. ],
                     [ 0. ,  0. ,  3. ,  0. ,  0. ],
                     [ 0. ,  0. ,  0. ,  3.5,  0. ],
                     [ 0. ,  0. ,  0. ,  0. ,  1. ]])
    )

    >>> af_tr3dorless, p = ni_affine_pixdim_from_affine(af_tr)
    >>> print af_tr3dorless
    AffineTransform(
       function_domain=CoordinateSystem(coord_names=('x+LR', 'y+PA', 'z+SI'), name='', coord_dtype=float64),
       function_range=CoordinateSystem(coord_names=('x+LR', 'y+PA', 'z+SI'), name='', coord_dtype=float64),
       affine=array([[ 2.,  0.,  0.,  0.],
                     [ 0., -2.,  0.,  0.],
                     [ 0.,  0.,  3.,  0.],
                     [ 0.,  0.,  0.,  1.]])
    )
    >>> print p
    [ 3.5]

    """ 

    if ((not isinstance(affine_transform, AT)) or
        (affine_transform.ndims[0] != affine_transform.ndims[1])):
        raise ValueError('affine_transform must be a square AffineTransform' + 
                         ' to save as a NIFTI file')
    
    ndim = affine_transform.ndims[0]
    ndim3 = min(ndim, 3)
    range_names = affine_transform.function_range.coord_names
    if range_names[:ndim3] not in [lps_output_coordnames[:ndim3],
                               ras_output_coordnames[:ndim3]]:
        if strict:
            raise ValueError('strict is true and the range is not LPS or RAS, assuming LPS')
        warnings.warn('range is not LPS or RAS, assuming LPS')
        range_names = list(range_names)
        range_names[:ndim3] = lps_output_coordnames[:ndim3]
        range_names = tuple(range_names)

    ndim = affine_transform.ndims[0]
    nifti_indim = 'ijk'[:ndim] + 'tuvw'[ndim3:ndim]
    nifti_outdim = range_names[:ndim3] + \
        ('t', 'u', 'v', 'w' )[ndim3:ndim]

    nifti_transform = AT(CS(nifti_indim),
                         CS(nifti_outdim),
                         affine_transform.affine)

    domain_names = affine_transform.function_domain.coord_names[:ndim3]
    nifti_transform = nifti_transform.renamed_domain(dict(zip('ijk'[:ndim3],
                                                         domain_names)))


    # now find the pixdims

    A = nifti_transform.affine[3:,3:]
    if (not np.allclose(np.diag(np.diag(A)), A)
        or not np.all(np.diag(A) > 0)):
        msg = "affine transformation matrix is not diagonal " + \
              " with positive entries on diagonal, some information lost"
        if strict:
            raise ValueError('strict is true and %s' % msg)
        warnings.warn(msg)
    pixdim = np.fabs(np.diag(A)[:-1])

    # find the 4x4 (or smaller)

    A3d = np.identity(ndim3+1)
    A3d[:ndim3,:ndim3] = nifti_transform.affine[:ndim3, :ndim3]
    A3d[:ndim3,-1] = nifti_transform.affine[:ndim3, -1]

    range_names = nifti_transform.function_range.coord_names[:ndim3]
    nifti_3dorless_transform = AT(CS(domain_names),
                                  CS(range_names),
                                  A3d)

    # if RAS, we flip, with a warning

    if range_names[:ndim3] == ras_output_coordnames[:ndim3]:
        signs = [-1,-1,1,1][:(ndim3+1)]
        # silly, but 1d case is handled for consistency
        if signs == [-1,-1]:
            signs = [-1,1]
        ras_to_lps = AT(CS(ras_output_coordnames[:ndim3]),
                        CS(lps_output_coordnames[:ndim3]),
                        np.diag(signs))
        warnings.warn('affine_transform has RAS output_range, flipping to LPS')
        nifti_3dorless_transform = compose(ras_to_lps, nifti_3dorless_transform)

    return nifti_3dorless_transform, pixdim
 def to_ni_image(self, t_idx, f_idx, grid_shape=None):
     m_arr = self.to_masked_array(t_idx, f_idx, grid_shape=grid_shape,
                                  fill_value=self.fill_value)
     meg2mri = self.beam.coreg.meg2mri
     return ni_api.Image(m_arr.filled(),
                         compose(meg2mri, self.beam.coordmap))
 def to_overlay(self, t_idx, f_idx, grid_spacing=None):
     m_arr = self.to_masked_array(t_idx, f_idx)
     meg2mri = self.beam.coreg.meg2mri
     img = ni_api.Image(m_arr,
                        compose(meg2mri, self.beam.coordmap))
     return img