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))
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)
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
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
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
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))