Source code for CPAC.generate_motion_statistics.utils
# Copyright (C) 2023 C-PAC Developers# This file is part of C-PAC.# C-PAC is free software: you can redistribute it and/or modify it under# the terms of the GNU Lesser General Public License as published by the# Free Software Foundation, either version 3 of the License, or (at your# option) any later version.# C-PAC is distributed in the hope that it will be useful, but WITHOUT# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public# License for more details.# You should have received a copy of the GNU Lesser General Public# License along with C-PAC. If not, see <https://www.gnu.org/licenses/>."""Utilities for motion parameters"""importnumpyasnp
[docs]defaffine_file_from_params_file(params_file:str,affine_file:str=None)->str:"""Convert a 6-DOF motion parameters array into a 4x4 affine matrix. Parameters ---------- params_file : str path to a motion parameter file (6 DOF, one timepoint per line) affine_file : str path to a 4x4 affine matrix file (the first 12 values, one timepoint per line), optional If included, comments will be passed on to filtered affine file Returns ------- affine_file : str path to a 4x4 affine matrix file (the first 12 values, one timepoint per line) """importosimportnumpyasnpfromCPAC.generate_motion_statistics.utilsimportaffine_from_params## load parameters file into arrayaffine=affine_from_params(np.genfromtxt(params_file))header=''ifaffine_file:# grab comment(s), if anywithopen(affine_file,'r',encoding='utf-8')as_f:header='\n'.join([lineforlinein_f.readlines()ifline.lstrip().startswith('#')])basename=(os.path.basename(affine_file)ifaffine_fileelsef'affine_{os.path.basename(params_file)}')affine_file=f'{os.getcwd()}/filtered_{basename}'# drop bottom [0, 0, 0, 1] row from each matrix# insert original comments, if any, as headernp.savetxt(affine_file,affine[:,:3].reshape(affine.shape[0],12),header=header,comments='')returnaffine_file
[docs]defaffine_from_params(params:np.ndarray)->np.ndarray:"""Convert a 6-DOF motion parameters array into a 4x4 affine matrix Parameters ---------- params : np.ndarray 2-dimensional array (t x 6) with the first dimension as timepoints and the second dimension containing these 6 elements (as output by `3dvolreg -1Dfile`): roll, pitch, yaw in degrees counterclockwise, and displacement in millimeters in the respective superior, left and posterior directions Returns ------- affine : np.ndarray t x 4 x 4 affine matrix with the upper-left 3 x 3 matrix encoding rotation, the top three values in the fourth column encoding translation and the bottom row being [0, 0, 0, 1] for each timepoint """fromnipype.algorithms.rapidartimport_get_affine_matrixfromscipy.spatial.transformimportRotationout=[]foriinrange(params.shape[0]):affine=_get_affine_matrix(params=params[i],source='AFNI')affine[:3,:3]=Rotation.from_euler("ZXY",-params[i,:3],degrees=True).as_matrix()out.append(affine)returnnp.array(out)
defload_mats(mat_dir:str)->np.ndarray:""" Given a directory of affince matrices as output by MCFLIRT, return an array of these matrices Parameters ---------- mat_dir : str path to MCFLIRT matrix output Returns ------- np.ndarray t x 4 x 4 affine matrix """frompathlibimportPathimportnumpyasnpmats=[]mat_paths=sorted(list(Path(mat_dir).glob("MAT_*")))forpathinmat_paths:mat=np.loadtxt(path)mats.append(mat)mats=np.stack(mats)returnmats