예제 #1
0
def test_inverse():
    r = rt.Registration(MAT)
    assert np.allclose(r.ref2src, np.linalg.inv(MAT))

    mc = rt.MotionCorrection(MATS)
    len(mc)
    for invm, m in zip(mc.inverse().src2ref, MATS):
        assert np.allclose(invm, np.linalg.inv(m))
예제 #2
0
def prepare_projector():
    """
    CLI for making a Projector
    """

    parser = CommonParser(
        'ref',
        'struct2ref',
        'flirt',
        'struct',
        'fsdir',
        'LPS',
        'LWS',
        'RPS',
        'RWS',
        'cores',
        'ones',
        'out',
        'super',
        description=(
            "Prepare a projector for a reference voxel grid and set "
            "of surfaces, and save in HDF5 format. This is a pre-processing "
            "step for performing surface-based analysis of volumetric data."))

    args = parser.parse_args()

    if args.flirt:
        struct2ref = rt.Registration.from_flirt(args.struc2ref, args.struct,
                                                args.ref).src2ref
    elif args.struct2ref == "I":
        struct2ref = rt.Registration.identity().src2ref
    else:
        struct2ref = rt.Registration(args.struct2ref).src2ref

    # Set up the hemispheres, reference ImageSpace, and prepare projector.
    spc = ImageSpace(args.ref)
    hemispheres = utils.load_surfs_to_hemispheres(**vars(args))
    hemispheres = [h.transform(struct2ref) for h in hemispheres]
    proj = projection.Projector(hemispheres, spc, args.super, args.cores,
                                args.ones)

    # Add default .h5 extension if needed, make outdir, save.
    outdir, outname = op.split(args.out)
    outbase, outext = op.splitext(outname)
    if not outext: outext = '.h5'
    if outdir: os.makedirs(outdir, exist_ok=True)
    out = op.join(outdir, outbase + outext)
    proj.save(out)
예제 #3
0
def test_type_promotion():
    r = rt.Registration(MAT)
    m = rt.MotionCorrection(MATS)
    x = r @ m
    assert type(x) is rt.MotionCorrection
    assert len(x) == len(MATS)
    x = m @ r
    assert type(x) is rt.MotionCorrection
    assert len(x) == len(MATS)

    x = m @ MAT
    assert type(x) is rt.MotionCorrection
    assert len(x) == len(MATS)
    x = MAT @ m
    assert type(x) is rt.MotionCorrection
    assert len(x) == len(MATS)

    x = MAT @ r
    assert type(x) is rt.Registration
    x = r @ MAT
    assert type(x) is rt.Registration
예제 #4
0
    def transform(self, trans, spc=None, factor=None, cores=mp.cpu_count(), ones=False):
        
        if spc is None: spc = self.spc 
        t = rt.Registration(trans)
        new_pvs = [ t.apply_to_array(pv.reshape(*spc.size,3), 
                                     self.spc, spc, cores=cores, 
                                     order=1
                                    ).reshape(-1,3)
                    for pv in self._hemi_pvs ]

        if factor is None:
            factor = np.ceil(3 * spc.vox_size)
        factor = (factor * np.ones(3)).astype(np.int32)

        proj = Projector.__new__(Projector)
        proj.hemi_dict = { h.side: h.transform(trans) for h in self.iter_hemis }
        proj.spc = spc 
        proj._hemi_pvs = new_pvs
        proj.vox_tri_mats = [] 
        proj.vtx_tri_mats = []
        ncores = cores if any([ h.inSurf._use_mp for h in self.iter_hemis ]) else 1 

        proj._assemble_vtx_vox_mats(factor, ncores, ones)
        return proj 
예제 #5
0
def complete(ref, struct2ref, **kwargs):
    """
    Estimate PVs for cortex and all structures identified by FIRST within 
    a reference image space. Use FAST to fill in non-surface PVs. 
    All arguments are kwargs.

    Required args: 
        ref (str/regtricks ImageSpace): voxel grid in which to estimate PVs. 
        struct2ref (str/np.array/rt.Registration): registration between space 
            of surface and reference (see -flirt and -stuct). Use 'I' for identity. 
        fslanat: path to fslanat directory. This REPLACES firstdir/fastdir/struct. 
        firstdir (str): FIRST directory in which .vtk surfaces are located
        fastdir (str): FAST directory in which _pve_0/1/2 are located 
        struct (str): path to structural image from which FIRST surfaces were dervied
        fsdir (str): FreeSurfer subject directory, OR: 
        LWS/LPS/RWS/RPS (str): paths to individual surfaces (L/R white/pial)

    Optional args: 
        flirt (bool): denoting struct2ref is FLIRT transform; if so, set struct. 
        coords (str): convention by which surface is defined: default is 'world' 
            (mm coords), for FIRST surfaces set as 'fsl' and provide struct argument 
        struct (str): path to structural image from which surfaces were derived
        cores (int): number of cores to use, default 8 
        supersample (int/array): single or 3 values, supersampling factor

    Returns: 
        (dict) PVs associated with each individual structure and 
            also the overall combined result ('stacked')
    """

    print("Estimating PVs for", ref.file_name)

    # If anat dir then various subdirs are loaded by @enforce_common_args
    # If not then direct load below
    if not bool(kwargs.get('fsdir')):
        if not all([bool(kwargs.get(k))
                    for k in ['LWS', 'LPS', 'RWS', 'RPS']]):
            raise RuntimeError("If fsdir not given, " +
                               "provide paths for LWS,LPS,RWS,RPS")

    if not bool(kwargs.get('fslanat')):
        if not (bool(kwargs.get('fastdir')) and bool(kwargs.get('firstdir'))):
            raise RuntimeError(
                "If not using anat dir, fastdir/firstdir required")

    # Resample FASTs to reference space. Then redefine CSF as 1-(GM+WM)
    fast_paths = utils._loadFASTdir(kwargs['fastdir'])
    fast_spc = fast_paths['FAST_GM']
    fast = np.stack([
        nibabel.load(fast_paths[f'FAST_{p}']).get_fdata()
        for p in ['GM', 'WM']
    ],
                    axis=-1)
    fasts_transformed = rt.Registration(struct2ref).apply_to_array(
        fast, fast_spc, ref)
    output = dict(FAST_GM=fasts_transformed[..., 0],
                  FAST_WM=fasts_transformed[..., 1])
    output['FAST_CSF'] = np.maximum(
        0, 1 - (output['FAST_WM'] + output['FAST_GM']))

    # Process subcortical structures first.
    FIRSTsurfs = utils._loadFIRSTdir(kwargs['firstdir'])
    subcortical = []
    struct_spc = ImageSpace(kwargs['struct'])
    for name, surf in FIRSTsurfs.items():
        s = Surface(surf, name)
        s = s.transform(struct_spc.FSL2world)
        subcortical.append(s)

    disp = "Structures found: " + ", ".join([s.name for s in subcortical] +
                                            ['Cortex'])
    print(disp)

    # To estimate against each subcortical structure, we apply the following
    # partial func to each using a map() call. Carry kwargs from this func
    desc = 'Subcortical structures'
    estimator = functools.partial(__structure_wrapper,
                                  ref=ref,
                                  struct2ref=struct2ref,
                                  **kwargs)

    # This is equivalent to a map(estimator, subcortical) call
    # All the extra stuff (tqdm etc) is used for progress bar
    results = [
        pv for _, pv in tqdm.tqdm(enumerate(map(estimator, subcortical)),
                                  total=len(subcortical),
                                  desc=desc,
                                  bar_format=core.BAR_FORMAT,
                                  ascii=True)
    ]

    output.update(dict(zip([s.name for s in subcortical], results)))

    # Now do the cortex, then stack the whole lot
    ctx = cortex(ref=ref, struct2ref=struct2ref, **kwargs)
    for i, t in enumerate(['_GM', '_WM', '_nonbrain']):
        output['cortex' + t] = (ctx[:, :, :, i])

    stacked = estimators.stack_images(
        {k: v
         for k, v in output.items() if k != 'BrStem'})
    output['GM'] = stacked[:, :, :, 0]
    output['WM'] = stacked[:, :, :, 1]
    output['nonbrain'] = stacked[:, :, :, 2]
    output['stacked'] = stacked

    return output
예제 #6
0
def test_fsl_inverse():
    r = rt.Registration(MAT)
    assert np.allclose(np.linalg.inv(r.to_fsl(SPC1, SPC2)),
                       r.inverse().to_fsl(SPC2, SPC1))