Beispiel #1
0
def subsample(bvecs, n_dirs, elec_points=None):
    """

    Generate a sub-sample of size n of directions from the provided bvecs

    Parameters
    ----------
    bvecs: int array (n by 3), a set of cartesian coordinates for a set of
    bvecs 
    n_dirs: int, how many bvecs to sub-sample from this set. 
    elec_points: optional, a set of points read from the camino points, using
    Jones (2003) algorithm for electro-static repulsion
    
    Returns 
    -------
    [x,y,z]: The coordinates of the sub-sample
    bvec_idx: The indices into the original bvecs that would give this
        sub-sample 
 
    Notes
    -----
    Directions are chosen from the camino-generated electro-static repulsion
    points in the directory camino_pts.

    """
    
    if elec_points is None:
        # We need a n by 3 here:
        xyz = ozu.get_camino_pts(n_dirs).T
    else:
        xyz = elec_points.copy()
            
    # Rotate all the points to align with the seed, the bvec relative to which
    # all the rest are chosen (lots going on in this one line):
    new_points = np.array(bvecs *
                          ozu.calculate_rotation(
                              bvecs[np.ceil(np.random.rand() *
                                            xyz.shape[0]).astype(int)],
                              xyz[0]))

    sample_bvecs = np.zeros((3, n_dirs))
    bvec_idx = []
    
    for vec in xrange(n_dirs):
        this = new_points[vec]
        delta = np.zeros(bvecs.shape[0])
        for j in xrange(bvecs.shape[0]):
            delta[j] = ozu.vector_angle(this, bvecs[j])

        this_idx = np.where(delta==np.min(delta))
        
        bvec_idx.append(this_idx)    
        sample_bvecs[:, vec] = bvecs[this_idx]

    return sample_bvecs, np.array(bvec_idx).squeeze()
Beispiel #2
0
def test_subsample():
    """
    Test subsampling
    """

    # Sub-sampling 100 out of a random collection of 150 unit-vectors:
    bvecs = np.array([ozu.unit_vector(x) for x in np.random.randn(3,150)])

    # The following runs through most of the module w/o verifying correctness:
    sub_sample = ozb.subsample(bvecs, 100)

    # optionally, you can provide elec_points as input. Here we test this with
    # the same points
    sub_sample = ozb.subsample(bvecs, 100, elec_points=ozu.get_camino_pts(100).T)
Beispiel #3
0
def test_subsample():
    """
    Test subsampling
    """

    # Sub-sampling 100 out of a random collection of 150 unit-vectors:
    bvecs = np.array([ozu.unit_vector(x) for x in np.random.randn(3, 150)])

    # The following runs through most of the module w/o verifying correctness:
    sub_sample = ozb.subsample(bvecs, 100)

    # optionally, you can provide elec_points as input. Here we test this with
    # the same points
    sub_sample = ozb.subsample(bvecs,
                               100,
                               elec_points=ozu.get_camino_pts(100).T)
Beispiel #4
0
def test_fodf_emd():
    """
    Test EMD on fODFs
    """
    bvecs = ozu.get_camino_pts(150)
    fodf1 = np.zeros(bvecs.shape[-1])
    fodf2 = np.zeros(bvecs.shape[-1])
    ii = np.random.randint(0, fodf1.shape[0])
    jj = np.random.randint(0, fodf2.shape[0])
    fodf1[ii] = 1
    fodf2[jj] = 1

    emd1 = pn.fODF_EMD(fodf1, fodf2, bvecs1=bvecs, bvecs2=bvecs)

    angles = np.arccos(np.dot(bvecs.T, bvecs))
    angles[np.isnan(angles)] = 0
    angles = np.min(np.array([angles, np.pi - angles]), 0)
    angles = angles.ravel()
    emd2 = pn.fODF_EMD(fodf1, fodf2, bvecs1=bvecs, dist=angles)

    npt.assert_equal(emd1, emd2)
Beispiel #5
0
def test_fodf_emd():
    """
    Test EMD on fODFs
    """
    bvecs = ozu.get_camino_pts(150)
    fodf1 = np.zeros(bvecs.shape[-1])
    fodf2 = np.zeros(bvecs.shape[-1])
    ii = np.random.randint(0, fodf1.shape[0])
    jj = np.random.randint(0, fodf2.shape[0])
    fodf1[ii] = 1
    fodf2[jj] = 1

    emd1 = pn.fODF_EMD(fodf1, fodf2, bvecs1=bvecs, bvecs2=bvecs)

    angles = np.arccos(np.dot(bvecs.T, bvecs))
    angles[np.isnan(angles)] = 0
    angles = np.min(np.array([angles, np.pi - angles]), 0)
    angles = angles.ravel()
    emd2 = pn.fODF_EMD(fodf1, fodf2, bvecs1=bvecs, dist=angles)

    npt.assert_equal(emd1, emd2)
Beispiel #6
0
def subsample(bvecs, n_dirs, elec_points=None):
    """

    Generate a sub-sample of size n of directions from the provided bvecs

    Parameters
    ----------
    bvecs: int array (n by 3), a set of cartesian coordinates for a set of
    bvecs 
    n_dirs: int, how many bvecs to sub-sample from this set. 
    elec_points: optional, a set of points read from the camino points, using
    Jones (2003) algorithm for electro-static repulsion
    
    Returns 
    -------
    [x,y,z]: The coordinates of the sub-sample
    bvec_idx: The indices into the original bvecs that would give this
        sub-sample 
 
    Notes
    -----
    Directions are chosen from the camino-generated electro-static repulsion
    points in the directory camino_pts.

    """
    
    if elec_points is None:
        # We need a n by 3 here:
        xyz = ozu.get_camino_pts(n_dirs).T
    else:
        xyz = elec_points.copy()
            
    # Rotate all the points to align with the seed, the bvec relative to which
    # all the rest are chosen (lots going on in this one line):
    rot_to_first = ozu.calculate_rotation(
                              bvecs[:, np.ceil(np.random.randint(xyz.shape[0]))],
                              xyz[0])

    new_points = np.dot(rot_to_first, bvecs).T

    sample_bvecs = np.zeros((3, n_dirs))
    bvec_idx = []

    potential_indices = np.arange(bvecs.shape[-1])
    for vec in xrange(n_dirs):
        this = new_points[vec]
        delta = np.zeros(potential_indices.shape)
        for j in range(delta.shape[0]):
            delta[j] = ozu.vector_angle(this, bvecs[:, j])

        this_idx = np.where(delta==np.min(delta))
        
        bvec_idx.append(potential_indices[this_idx])    
        sample_bvecs[:, vec] = np.squeeze(bvecs[:, this_idx])

        # Remove bvecs that you've used, so that you don't have them more than
        # once: 
        bvecs = np.hstack([bvecs[:, :this_idx[0]],bvecs[:, this_idx[0]+1:]])
        potential_indices = np.hstack([potential_indices[:this_idx[0]],
                                            potential_indices[this_idx[0]+1:]])
        
    return sample_bvecs, np.array(bvec_idx).squeeze()
Beispiel #7
0
    def __init__(self,
                 data,
                 bvecs,
                 bvals,
                 params_file=None,
                 axial_diffusivity=AD,
                 radial_diffusivity=RD,
                 affine=None,
                 mask=None,
                 scaling_factor=SCALE_FACTOR,
                 sub_sample=None,
                 over_sample=None,
                 mode='relative_signal',
                 iso_diffusivity=None,
                 verbose=True):

        """
        Initialize a CanonicalTensorModel class instance.

        Parameters
        ----------

        params_file: str, optional
             full path to the name of the file in which to save the model
             parameters, once a model is fit. 

        over_sample: optional, int.
           Sometimes you might want to probe the sphere at a higher resolution
           than that provided by the measurement. You can do that using two
           possible sources of information. The first is the camino points,
           which ship together with osmosis and are used for the boot-strapping
           (see osmosis.boot). These are used for integers smaller than 150,
           for 246 and for 755. The other sources of information are the
           symmetric spheres provided as part of dipy. These are used if 362 or
           642 are provided. Note that these might be problematic, because they
           contain polar opposite points, so use with caution.

        mode: string, optional
        This can take one of several values, determining the form of the
        regressors and the form of the signal to fit to.

        'relative_signal': The fit is to $\frac{S}{S_0}$ and the regressors
        are the relative signal predicted for a canonical tensor and the
        relative signal predicted for a isotropic diffusivity compartment:

        .. math::

           \frac{S}{S_0} = \beta_1 e^{-bD} + \beta_2 e^{-b\vec{b}Q\vec{b}^t}

    
        'signal_attenuation': The fit is to $1-\frac{S}{S_0}$ and the
        regressors are the signal attenuation for the canonical tensor and the
        signal attenuation due to isotropic diffusion:

        .. math::

             1-\frac{S}{S_0} = \beta_1 (1-e^{-bD}) + \beta_2 (1-e^{-b\vec{b} Q \vec{b}^t})

        'normalize': in this case, we fit to $\frac{S}{S_0}$, but our regressor
        set is normalized to maximum of 1 in each columns. This affects the
        values of the weights, and also the goodness-of-fit (because of the
        relative scaling of the regressors in the OLS). The equation in
        this case is: 

        .. math::

             \frac{S}{S_0} = \beta_1 + \beta_2 \frac{e^{-b\vec{b} Q \vec{b}^t}}{max(e^{-b\vec{b} Q \vec{b}^t})}


        'log': in this case, we fit to $log(\frac{S}{S_0})$ and our regressors
        are the exponents:

        .. math::

            log(\frac{S}{S_0}) = \beta_1 -bD + \beta_1 -b\vec{b}Q\vec{b}^t

        iso_diffusivity: optional, float
            What the diffusivity of the isotropic component should be set
            to. This is irrelevant for the 'normalize' mode. Defaults to be
            equal to the axial_diffusivity
              
        """
        
        # Initialize the super-class:
        BaseModel.__init__(self,
                            data,
                            bvecs,
                            bvals,
                            affine=affine,
                            mask=mask,
                            scaling_factor=scaling_factor,
                            sub_sample=sub_sample,
                            params_file=params_file,
                            verbose=verbose)

        self.ad = axial_diffusivity
        self.rd = radial_diffusivity

        if iso_diffusivity is None:
           iso_diffusivity = axial_diffusivity
        self.iso_diffusivity = iso_diffusivity

        if over_sample is not None:
            # Symmetric spheres from dipy: 
            if over_sample in[362, 642]:
                # We want to get these vertices:
                verts = dpd.get_sphere('symmetric%s'%over_sample).vertices
                # Their convention is transposed relative to ours:
                self.rot_vecs = verts.T
            elif (isinstance(over_sample, int) and (over_sample<=150 or
                                                    over_sample in [246,755])):
                self.rot_vecs = ozu.get_camino_pts(over_sample)
            elif over_sample== 'quad132':
                pp = os.path.split(oz.__file__)[0]+'/data/SparseKernelModel/'
                self.rot_vecs = np.loadtxt(pp + 'qsph1-16-132DP.dat')[:,:-1].T
            else:
                e_s = "You asked to sample the sphere in %s"%over_sample
                e_s += " different directions. Can only do that for n<=150"
                e_s += " or n in [246, 362, 642, 755]"
                raise ValueError(e_s)
        else:
            self.rot_vecs = self.bvecs[:,self.b_idx]

        if mode not in ['relative_signal',
                        'signal_attenuation',
                        'normalize',
                        'log']:
            raise ValueError("Not a recognized mode of CanonicalTensorModel")

        self.mode = mode
        self.iso_diffusivity = iso_diffusivity
Beispiel #8
0
def subsample(bvecs, n_dirs, elec_points=None):
    """

    Generate a sub-sample of size n of directions from the provided bvecs

    Parameters
    ----------
    bvecs: int array (n by 3), a set of cartesian coordinates for a set of
    bvecs 
    n_dirs: int, how many bvecs to sub-sample from this set. 
    elec_points: optional, a set of points read from the camino points, using
    Jones (2003) algorithm for electro-static repulsion
    
    Returns 
    -------
    [x,y,z]: The coordinates of the sub-sample
    bvec_idx: The indices into the original bvecs that would give this
        sub-sample 
 
    Notes
    -----
    Directions are chosen from the camino-generated electro-static repulsion
    points in the directory camino_pts.

    """

    if elec_points is None:
        # We need a n by 3 here:
        xyz = ozu.get_camino_pts(n_dirs).T
    else:
        xyz = elec_points.copy()

    # Rotate all the points to align with the seed, the bvec relative to which
    # all the rest are chosen (lots going on in this one line):
    rot_to_first = ozu.calculate_rotation(
        bvecs[:, np.ceil(np.random.randint(xyz.shape[0]))], xyz[0])

    new_points = np.dot(rot_to_first, bvecs).T

    sample_bvecs = np.zeros((3, n_dirs))
    bvec_idx = []

    potential_indices = np.arange(bvecs.shape[-1])
    for vec in xrange(n_dirs):
        this = new_points[vec]
        delta = np.zeros(potential_indices.shape)
        for j in range(delta.shape[0]):
            delta[j] = ozu.vector_angle(this, bvecs[:, j])

        this_idx = np.where(delta == np.min(delta))

        bvec_idx.append(potential_indices[this_idx])
        sample_bvecs[:, vec] = np.squeeze(bvecs[:, this_idx])

        # Remove bvecs that you've used, so that you don't have them more than
        # once:
        bvecs = np.hstack([bvecs[:, :this_idx[0]], bvecs[:, this_idx[0] + 1:]])
        potential_indices = np.hstack([
            potential_indices[:this_idx[0]],
            potential_indices[this_idx[0] + 1:]
        ])

    return sample_bvecs, np.array(bvec_idx).squeeze()
Beispiel #9
0
    def __init__(self,
                 data,
                 bvecs,
                 bvals,
                 params_file=None,
                 axial_diffusivity=AD,
                 radial_diffusivity=RD,
                 affine=None,
                 mask=None,
                 scaling_factor=SCALE_FACTOR,
                 sub_sample=None,
                 over_sample=None,
                 mode='relative_signal',
                 iso_diffusivity=None,
                 verbose=True):
        """
        Initialize a CanonicalTensorModel class instance.

        Parameters
        ----------

        params_file: str, optional
             full path to the name of the file in which to save the model
             parameters, once a model is fit. 

        over_sample: optional, int.
           Sometimes you might want to probe the sphere at a higher resolution
           than that provided by the measurement. You can do that using two
           possible sources of information. The first is the camino points,
           which ship together with osmosis and are used for the boot-strapping
           (see osmosis.boot). These are used for integers smaller than 150,
           for 246 and for 755. The other sources of information are the
           symmetric spheres provided as part of dipy. These are used if 362 or
           642 are provided. Note that these might be problematic, because they
           contain polar opposite points, so use with caution.

        mode: string, optional
        This can take one of several values, determining the form of the
        regressors and the form of the signal to fit to.

        'relative_signal': The fit is to $\frac{S}{S_0}$ and the regressors
        are the relative signal predicted for a canonical tensor and the
        relative signal predicted for a isotropic diffusivity compartment:

        .. math::

           \frac{S}{S_0} = \beta_1 e^{-bD} + \beta_2 e^{-b\vec{b}Q\vec{b}^t}

    
        'signal_attenuation': The fit is to $1-\frac{S}{S_0}$ and the
        regressors are the signal attenuation for the canonical tensor and the
        signal attenuation due to isotropic diffusion:

        .. math::

             1-\frac{S}{S_0} = \beta_1 (1-e^{-bD}) + \beta_2 (1-e^{-b\vec{b} Q \vec{b}^t})

        'normalize': in this case, we fit to $\frac{S}{S_0}$, but our regressor
        set is normalized to maximum of 1 in each columns. This affects the
        values of the weights, and also the goodness-of-fit (because of the
        relative scaling of the regressors in the OLS). The equation in
        this case is: 

        .. math::

             \frac{S}{S_0} = \beta_1 + \beta_2 \frac{e^{-b\vec{b} Q \vec{b}^t}}{max(e^{-b\vec{b} Q \vec{b}^t})}


        'log': in this case, we fit to $log(\frac{S}{S_0})$ and our regressors
        are the exponents:

        .. math::

            log(\frac{S}{S_0}) = \beta_1 -bD + \beta_1 -b\vec{b}Q\vec{b}^t

        iso_diffusivity: optional, float
            What the diffusivity of the isotropic component should be set
            to. This is irrelevant for the 'normalize' mode. Defaults to be
            equal to the axial_diffusivity
              
        """

        # Initialize the super-class:
        BaseModel.__init__(self,
                           data,
                           bvecs,
                           bvals,
                           affine=affine,
                           mask=mask,
                           scaling_factor=scaling_factor,
                           sub_sample=sub_sample,
                           params_file=params_file,
                           verbose=verbose)

        self.ad = axial_diffusivity
        self.rd = radial_diffusivity

        if iso_diffusivity is None:
            iso_diffusivity = axial_diffusivity
        self.iso_diffusivity = iso_diffusivity

        if over_sample is not None:
            # Symmetric spheres from dipy:
            if over_sample in [362, 642]:
                # We want to get these vertices:
                verts = dpd.get_sphere('symmetric%s' % over_sample).vertices
                # Their convention is transposed relative to ours:
                self.rot_vecs = verts.T
            elif (isinstance(over_sample, int)
                  and (over_sample <= 150 or over_sample in [246, 755])):
                self.rot_vecs = ozu.get_camino_pts(over_sample)
            elif over_sample == 'quad132':
                pp = os.path.split(oz.__file__)[0] + '/data/SparseKernelModel/'
                self.rot_vecs = np.loadtxt(pp + 'qsph1-16-132DP.dat')[:, :-1].T
            else:
                e_s = "You asked to sample the sphere in %s" % over_sample
                e_s += " different directions. Can only do that for n<=150"
                e_s += " or n in [246, 362, 642, 755]"
                raise ValueError(e_s)
        else:
            self.rot_vecs = self.bvecs[:, self.b_idx]

        if mode not in [
                'relative_signal', 'signal_attenuation', 'normalize', 'log'
        ]:
            raise ValueError("Not a recognized mode of CanonicalTensorModel")

        self.mode = mode
        self.iso_diffusivity = iso_diffusivity