Module xelo2.bids.io.parrec
Expand source code
from logging import getLogger
from pathlib import Path
from numpy import unique
from nibabel.parrec import parse_PAR_header
from nibabel.cmdline.parrec2nii import get_opt_parser, proc_file, verbose
from nibabel.mriutils import calculate_dwell_time
from tempfile import mkdtemp
lg = getLogger(__name__)
MR_TYPES = {
0: 'magnitude',
3: 'phase',
-1: 'reconstructed', # relevant for MP2RAGE
}
def convert_parrec_nibabel(par_file, MagneticFieldStrength=None):
"""
"""
input_par = Path(par_file).resolve()
hdr = parse_PAR(input_par, MagneticFieldStrength)
tmp_dir = mkdtemp()
lg.debug(f'Temporary directory for PAR/REC conversion: {tmp_dir}')
parser = get_opt_parser()
(opts, infiles) = parser.parse_args([
'--output-dir=' + tmp_dir,
'--compressed',
'--permit-truncated',
'--store-header',
'--strict-sort', # necessary for magnitute / phase
] + [str(input_par), ]
)
verbose.switch = opts.verbose
proc_file(infiles[0], opts)
output = next(Path(tmp_dir).glob('*.nii.gz'))
return output, hdr
def parse_PAR(par_file, MagneticFieldStrength=None):
"""Get some useful information from PAR file. It's quite slow but reading
the PAR file twice seems the best solution.
Returns
-------
dict
"n_dynamics" : int
actual number of recorded dynamics (not the planned number of dyns)
"EffectiveEchoSpacing" : float
use nibabel to compute EffectiveEchoSpacing (dwell time in nibabel is not the same as DwellTime in BIDS)
"""
out = {}
with par_file.open() as f:
hdr, info = parse_PAR_header(f)
out['RepetitionTime'] = hdr['repetition_time'].item() / 1000
out['n_dynamics'] = info['dynamic scan number'].max()
out['EchoTime'] = info['echo_time'][0] / 1000 # ms -> s
out['n_slices'] = info['slice number'].max()
out['FlipAngle'] = info['image_flip_angle'][0]
if MagneticFieldStrength is not None:
MagneticFieldStrength = float(MagneticFieldStrength[:-1])
out['EffectiveEchoSpacing'] = calculate_dwell_time(hdr['water_fat_shift'], hdr['epi_factor'], MagneticFieldStrength) / 1000
try:
out['image_types'] = [MR_TYPES[x] for x in unique(info['image_type_mr'])]
except KeyError:
raise ValueError('Unrecognized "image_type_mr" in PAR file. Please add it to MR_TYPES in this function')
return out
Functions
def convert_parrec_nibabel(par_file, MagneticFieldStrength=None)
-
Expand source code
def convert_parrec_nibabel(par_file, MagneticFieldStrength=None): """ """ input_par = Path(par_file).resolve() hdr = parse_PAR(input_par, MagneticFieldStrength) tmp_dir = mkdtemp() lg.debug(f'Temporary directory for PAR/REC conversion: {tmp_dir}') parser = get_opt_parser() (opts, infiles) = parser.parse_args([ '--output-dir=' + tmp_dir, '--compressed', '--permit-truncated', '--store-header', '--strict-sort', # necessary for magnitute / phase ] + [str(input_par), ] ) verbose.switch = opts.verbose proc_file(infiles[0], opts) output = next(Path(tmp_dir).glob('*.nii.gz')) return output, hdr
def parse_PAR(par_file, MagneticFieldStrength=None)
-
Get some useful information from PAR file. It's quite slow but reading the PAR file twice seems the best solution.
Returns
dict
- "n_dynamics" : int actual number of recorded dynamics (not the planned number of dyns) "EffectiveEchoSpacing" : float use nibabel to compute EffectiveEchoSpacing (dwell time in nibabel is not the same as DwellTime in BIDS)
Expand source code
def parse_PAR(par_file, MagneticFieldStrength=None): """Get some useful information from PAR file. It's quite slow but reading the PAR file twice seems the best solution. Returns ------- dict "n_dynamics" : int actual number of recorded dynamics (not the planned number of dyns) "EffectiveEchoSpacing" : float use nibabel to compute EffectiveEchoSpacing (dwell time in nibabel is not the same as DwellTime in BIDS) """ out = {} with par_file.open() as f: hdr, info = parse_PAR_header(f) out['RepetitionTime'] = hdr['repetition_time'].item() / 1000 out['n_dynamics'] = info['dynamic scan number'].max() out['EchoTime'] = info['echo_time'][0] / 1000 # ms -> s out['n_slices'] = info['slice number'].max() out['FlipAngle'] = info['image_flip_angle'][0] if MagneticFieldStrength is not None: MagneticFieldStrength = float(MagneticFieldStrength[:-1]) out['EffectiveEchoSpacing'] = calculate_dwell_time(hdr['water_fat_shift'], hdr['epi_factor'], MagneticFieldStrength) / 1000 try: out['image_types'] = [MR_TYPES[x] for x in unique(info['image_type_mr'])] except KeyError: raise ValueError('Unrecognized "image_type_mr" in PAR file. Please add it to MR_TYPES in this function') return out