def fmap_echotimes(src_phase_json_fname): """ Extract TE1 and TE2 from mag and phase MEGE fieldmap pairs :param src_phase_json_fname: str :return: """ # Init returned TEs te1, te2 = 0.0, 0.0 if os.path.isfile(src_phase_json_fname): # Read phase image metadata phase_dict = bio.read_json(src_phase_json_fname) # Populate series info dictionary from dcm2niix output filename info = bio.parse_dcm2niix_fname(src_phase_json_fname) # Siemens: Magnitude 1 series number is one less than phasediff series number mag1_ser_no = str(int(info['SerNo']) - 1) # Construct dcm2niix mag1 JSON filename # Requires dicm2niix v1.0.20180404 or later for echo number suffix '_e1' src_mag1_json_fname = info['SubjName'] + '--' + info['SerDesc'] + '--' + \ info['SeqName'] + '--' + mag1_ser_no + '_e1.json' src_mag1_json_path = os.path.join( os.path.dirname(src_phase_json_fname), src_mag1_json_fname) # Read mag1 metadata mag1_dict = bio.read_json(src_mag1_json_path) # Add te1 key and rename TE2 key if mag1_dict: te1 = mag1_dict['EchoTime'] te2 = phase_dict['EchoTime'] else: print( '*** Could not determine echo times multiecho fieldmap - using 0.0 ' ) else: print('* Fieldmap phase difference sidecar not found : ' + src_phase_json_fname) return te1, te2
def get_acq_time(json_file): """ Extract acquisition time from JSON sidecar of Nifti file :param json_file: str, JSON sidecar filename :return: acq_time: int, integer datetime """ info = bio.read_json(json_file) return info['AcquisitionTime']
def fmap_echotimes(src_phase_json_fname): """ Extract TE1 and TE2 from mag and phase MEGE fieldmap pairs :param src_phase_json_fname: str :return: """ # Init returned TEs te1, te2 = 0.0, 0.0 if os.path.isfile(src_phase_json_fname): # Read phase image metadata phase_dict = bio.read_json(src_phase_json_fname) # Populate series info dictionary from dcm2niix output filename info = bio.parse_dcm2niix_fname(src_phase_json_fname) # Siemens: Magnitude 1 series number is one less than phasediff series number mag1_ser_no = str(int(info['SerNo']) - 1) # Construct dcm2niix mag1 JSON filename # Requires dicm2niix v1.0.20180404 or later for echo number suffix '_e1' src_mag1_json_fname = info['SubjName'] + '--' + info['SerDesc'] + '--' + \ info['SeqName'] + '--' + mag1_ser_no + '_e1.json' src_mag1_json_path = os.path.join(os.path.dirname(src_phase_json_fname), src_mag1_json_fname) # Read mag1 metadata mag1_dict = bio.read_json(src_mag1_json_path) # Add te1 key and rename TE2 key if mag1_dict: te1 = mag1_dict['EchoTime'] te2 = phase_dict['EchoTime'] else: print('*** Could not determine echo times multiecho fieldmap - using 0.0 ') else: print('* Fieldmap phase difference sidecar not found : ' + src_phase_json_fname) return te1, te2
def get_acq_time(json_file): """ Extract acquisition time from JSON sidecar of Nifti file :param json_file: str, JSON sidecar filename :return: acq_time: int, integer datetime """ info = bio.read_json(json_file) if 'AcquisitionTime' in info: acq_time = info['AcquisitionTime'] else: print('* AcquisitionTime not found in {}'.format(json_file)) acq_time = "00:00:00.00" return acq_time
def purpose_handling(bids_purpose, bids_intendedfor, seq_name, work_nii_fname, work_json_fname, bids_nii_fname, bids_json_fname, overwrite=False): """ Special handling for each image purpose (func, anat, fmap, dwi, etc) :param bids_purpose: str :param bids_intendedfor: str :param seq_name: str :param work_nii_fname: str :param work_json_fname: str :param bids_nii_fname: str :param bids_json_fname: str :param overwrite: bool :return: """ # Init DWI sidecars work_bval_fname = [] work_bvec_fname = [] bids_bval_fname = [] bids_bvec_fname = [] # Load the JSON sidecar bids_info = bio.read_json(work_json_fname) if bids_purpose == 'func': if seq_name == 'EP': print(' EPI detected') create_events_template(bids_nii_fname, overwrite) # Add taskname to BIDS JSON sidecar bids_keys = bio.parse_bids_fname(bids_nii_fname) if 'task' in bids_keys: bids_info['TaskName'] = bids_keys['task'] else: bids_info['TaskName'] = 'unknown' elif bids_purpose == 'fmap': # Add IntendedFor field if requested through protocol translator if 'UNASSIGNED' not in bids_intendedfor: bids_info['IntendedFor'] = bids_intendedfor # Check for MEGE vs SE-EPI fieldmap images # MEGE will have a 'GR' sequence, SE-EPI will have 'EP' print(' Identifying fieldmap image type') if seq_name == 'GR': print(' GRE detected') print(' Identifying magnitude and phase images') # Siemens: Dual gradient echo fieldmaps reconstruct to three series # (Requires dcm2nixx v1.0.20180404 or later for echo number suffix) # *--GR--<serno>_e1.<ext> : magnitude image from echo 1 # *--GR--<serno>_e2.<ext> : magnitude image from echo 2 # *--GR--<serno+1>_ph.<ext> : inter-echo phase difference # Pull dcm2niix filename info work_info = bio.parse_dcm2niix_fname(work_nii_fname) if 'e1' in work_info['Suffix']: print(' Echo 1 magnitude detected') # Replace existing contrast suffix (if any) with '_magnitude1' bids_nii_fname = replace_contrast(bids_nii_fname, 'magnitude1') bids_json_fname = [] # Do not copy sidecar elif 'e2' in work_info['Suffix']: print(' Echo 2 magnitude detected') # Replace existing contrast suffix (if any) with '_magnitude1' bids_nii_fname = replace_contrast(bids_nii_fname, 'magnitude2') bids_json_fname = [] # Do not copy sidecar elif 'ph' in work_info['Suffix']: print(' Interecho phase difference detected') # Replace existing contrast suffix (if any) with '_phasediff' bids_nii_fname = replace_contrast(bids_nii_fname, 'phasediff') bids_json_fname = replace_contrast(bids_json_fname, 'phasediff') # Extract TE1 and TE2 from mag and phase JSON sidecars te1, te2 = fmap_echotimes(work_json_fname) bids_info['EchoTime1'] = te1 bids_info['EchoTime2'] = te2 else: print('* Magnitude or phase image not found - skipping') bids_nii_fname = [] bids_json_fname = [] elif seq_name == 'EP': print(' EPI detected') else: print(' Unrecognized fieldmap detected') print(' Simply copying image and sidecar to fmap directory') elif bids_purpose == 'anat': if seq_name == 'GR_IR': print( ' IR-prepared GRE detected - likely T1w MP-RAGE or equivalent' ) elif seq_name == 'SE': print(' Spin echo detected - likely T1w or T2w anatomic image') elif seq_name == 'GR': print(' Gradient echo detected') elif bids_purpose == 'dwi': # Fill DWI bval and bvec working and source filenames # Non-empty filenames trigger the copy below work_bval_fname = str(work_json_fname.replace('.json', '.bval')) bids_bval_fname = str(bids_json_fname.replace('dwi.json', 'dwi.bval')) work_bvec_fname = str(work_json_fname.replace('.json', '.bvec')) bids_bvec_fname = str(bids_json_fname.replace('dwi.json', 'dwi.bvec')) # Populate BIDS source directory with Nifti images, JSON and DWI sidecars print(' Populating BIDS source directory') if bids_nii_fname: bio.safe_copy(work_nii_fname, str(bids_nii_fname), overwrite) if bids_json_fname: bio.write_json(bids_json_fname, bids_info, overwrite) if bids_bval_fname: bio.safe_copy(work_bval_fname, bids_bval_fname, overwrite) if bids_bvec_fname: bio.safe_copy(work_bvec_fname, bids_bvec_fname, overwrite)
def purpose_handling(bids_purpose, bids_intendedfor, seq_name, work_nii_fname, work_json_fname, bids_nii_fname, bids_json_fname, overwrite=False): """ Special handling for each image purpose (func, anat, fmap, dwi, etc) :param bids_purpose: str :param bids_intendedfor: str :param seq_name: str :param work_nii_fname: str :param work_json_fname: str :param bids_nii_fname: str :param bids_json_fname: str :param overwrite: bool :return: """ # Init DWI sidecars work_bval_fname = [] work_bvec_fname = [] bids_bval_fname = [] bids_bvec_fname = [] # Load the JSON sidecar bids_info = bio.read_json(work_json_fname) if bids_purpose == 'func': if seq_name == 'EP': print(' EPI detected') create_events_template(bids_nii_fname, overwrite) # Add taskname to BIDS JSON sidecar bids_keys = bio.parse_bids_fname(bids_nii_fname) if 'task' in bids_keys: bids_info['TaskName'] = bids_keys['task'] else: bids_info['TaskName'] = 'unknown' elif bids_purpose == 'fmap': # Add IntendedFor field if requested through protocol translator if 'UNASSIGNED' not in bids_intendedfor: bids_info['IntendedFor'] = bids_intendedfor # Check for MEGE vs SE-EPI fieldmap images # MEGE will have a 'GR' sequence, SE-EPI will have 'EP' print(' Identifying fieldmap image type') if seq_name == 'GR': print(' GRE detected') print(' Identifying magnitude and phase images') # Siemens: Dual gradient echo fieldmaps reconstruct to three series # (Requires dcm2nixx v1.0.20180404 or later for echo number suffix) # *--GR--<serno>_e1.<ext> : magnitude image from echo 1 # *--GR--<serno>_e2.<ext> : magnitude image from echo 2 # *--GR--<serno+1>_ph.<ext> : inter-echo phase difference # Pull dcm2niix filename info work_info = bio.parse_dcm2niix_fname(work_nii_fname) if 'e1' in work_info['Suffix']: print(' Echo 1 magnitude detected') # Replace existing contrast suffix (if any) with '_magnitude1' bids_nii_fname = replace_contrast(bids_nii_fname, 'magnitude1') bids_json_fname = [] # Do not copy sidecar elif 'e2' in work_info['Suffix']: print(' Echo 2 magnitude detected') # Replace existing contrast suffix (if any) with '_magnitude1' bids_nii_fname = replace_contrast(bids_nii_fname, 'magnitude2') bids_json_fname = [] # Do not copy sidecar elif 'ph' in work_info['Suffix']: print(' Interecho phase difference detected') # Replace existing contrast suffix (if any) with '_phasediff' bids_nii_fname = replace_contrast(bids_nii_fname, 'phasediff') bids_json_fname = replace_contrast(bids_json_fname, 'phasediff') # Extract TE1 and TE2 from mag and phase JSON sidecars te1, te2 = fmap_echotimes(work_json_fname) bids_info['EchoTime1'] = te1 bids_info['EchoTime2'] = te2 else: print('* Magnitude or phase image not found - skipping') bids_nii_fname = [] bids_json_fname = [] elif seq_name == 'EP': print(' EPI detected') else: print(' Unrecognized fieldmap detected') print(' Simply copying image and sidecar to fmap directory') elif bids_purpose == 'anat': if seq_name == 'GR_IR': print(' IR-prepared GRE detected - likely T1w MP-RAGE or equivalent') elif seq_name == 'SE': print(' Spin echo detected - likely T1w or T2w anatomic image') elif seq_name == 'GR': print(' Gradient echo detected') elif bids_purpose == 'dwi': # Fill DWI bval and bvec working and source filenames # Non-empty filenames trigger the copy below work_bval_fname = str(work_json_fname.replace('.json', '.bval')) bids_bval_fname = str(bids_json_fname.replace('dwi.json', 'dwi.bval')) work_bvec_fname = str(work_json_fname.replace('.json', '.bvec')) bids_bvec_fname = str(bids_json_fname.replace('dwi.json', 'dwi.bvec')) # Populate BIDS source directory with Nifti images, JSON and DWI sidecars print(' Populating BIDS source directory') if bids_nii_fname: bio.safe_copy(work_nii_fname, str(bids_nii_fname), overwrite) if bids_json_fname: bio.write_json(bids_json_fname, bids_info, overwrite) if bids_bval_fname: bio.safe_copy(work_bval_fname, bids_bval_fname, overwrite) if bids_bvec_fname: bio.safe_copy(work_bvec_fname, bids_bvec_fname, overwrite)