def parse_one(self): """ Composer function, parses all metadata that can be parsed from a single dicom. Called by NIMSDicom init, if dicom manufacturer is Siemens. """ mr.parse_standard_mr_tags(self) self.psd_name = self.getelem( self._hdr, 'CsaSeries.MrPhoenixProtocol.tSequenceFileName', str, '').lower().replace('%', '', 1) self.psd_iname = self.getelem(self._hdr, 'SeriesDescription') self.fov_x = self.getelem( self._hdr, 'CsaSeries.MrPhoenixProtocol.sSliceArray.asSlice[0].dPhaseFOV', float) # XXX fov-x = PhaseFOV? self.fov_y = self.getelem( self._hdr, 'CsaSeries.MrPhoenixProtocol.sSliceArray.asSlice[0].dReadoutFOV', float) # XXX fov-y = ReadoutFOV? self.receive_coil_name = self.getelem(self._hdr, 'CsaImage.ImaCoilString') slice_duration = self.getelem(self._hdr, 'CsaImage.SliceMeasurementDuration', float, 0.) self.slice_duration = slice_duration / 1e6 if slice_duration else None self.prescribed_duration = self.getelem( self._hdr, 'CsaSeries.MrPhoenixProtocol.lScanTimeSec') # FIXME self.duration = self.getelem( self._hdr, 'CsaSeries.MrPhoenixProtocol.lTotalScanTimeSec' ) # FIXME: not guaranteed self.acq_no = None # siemens acq # indicates the brain volume instance. varies within one scan. # this is not an ideal solution, as it assumes that EPI timeserise are always stored in mosaic # for mosaics, lReps = prescribed timepoints. non-mosaics and non-timeseries will not have this tag lRep = self.getelem(self._hdr, 'CsaSeries.MrPhoenixProtocol.lRepetitions', int) self.num_timepoints = (lRep + 1) if lRep else None self.dwi_dirs = self.getelem( self._hdr, 'CsaSeries.MrPhoenixProtocol.sDiffusion.lDiffDirections', int, None) if (self.dwi_dirs or 0) > 1: self.is_dwi = True self.num_timepoints = 1 # some siemens MR dicoms are not reconstructable if 'CSAPARALLEL' in self.image_type: self.is_non_image = True if 'POSDISP' in self.image_type: self.is_non_image = True if self.image_type == SIEMENS_TYPE_DIS2D: # had 2 image orientations, and other metdata that varied between dicoms, and is not a localizer. AFNI cannot reconstsruct. # this is a specific hack fix. A more general fix is to check each dicom to see if the orientation matches the first dicom # but checking EVERY dicom isn't very ideal solution (some datasets might have an ENORMOUS number of dicoms) self.is_non_image = True infer_psd_type(self) mr.adjust_fov_acqmat(self) mr.infer_scan_type(self)
def parse_one(self): """ Composer function, parses all metadata that can be parsed from a single dicom. Called by NIMSDicom init, if dicom manufacturer is Siemens. """ mr.parse_standard_mr_tags(self) self.psd_name = self.getelem(self._hdr, 'CsaSeries.MrPhoenixProtocol.tSequenceFileName', str, '').lower().replace('%', '', 1) self.psd_iname = self.getelem(self._hdr, 'SeriesDescription') self.fov_x = self.getelem(self._hdr, 'CsaSeries.MrPhoenixProtocol.sSliceArray.asSlice[0].dPhaseFOV', float) # XXX fov-x = PhaseFOV? self.fov_y = self.getelem(self._hdr, 'CsaSeries.MrPhoenixProtocol.sSliceArray.asSlice[0].dReadoutFOV', float) # XXX fov-y = ReadoutFOV? self.receive_coil_name = self.getelem(self._hdr, 'CsaImage.ImaCoilString') slice_duration = self.getelem(self._hdr, 'CsaImage.SliceMeasurementDuration', float, 0.) self.slice_duration = slice_duration / 1e6 if slice_duration else None self.prescribed_duration = self.getelem(self._hdr, 'CsaSeries.MrPhoenixProtocol.lScanTimeSec') # FIXME self.duration = self.getelem(self._hdr, 'CsaSeries.MrPhoenixProtocol.lTotalScanTimeSec') # FIXME: not guaranteed self.acq_no = None # siemens acq # indicates the brain volume instance. varies within one scan. # this is not an ideal solution, as it assumes that EPI timeserise are always stored in mosaic # for mosaics, lReps = prescribed timepoints. non-mosaics and non-timeseries will not have this tag lRep = self.getelem(self._hdr, 'CsaSeries.MrPhoenixProtocol.lRepetitions', int) self.num_timepoints = (lRep + 1) if lRep else None self.dwi_dirs = self.getelem(self._hdr, 'CsaSeries.MrPhoenixProtocol.sDiffusion.lDiffDirections', int, None) if (self.dwi_dirs or 0) > 1: self.is_dwi = True self.num_timepoints = 1 # some siemens MR dicoms are not reconstructable if 'CSAPARALLEL' in self.image_type: self.is_non_image = True if 'POSDISP' in self.image_type: self.is_non_image = True if self.image_type == SIEMENS_TYPE_DIS2D: # had 2 image orientations, and other metdata that varied between dicoms, and is not a localizer. AFNI cannot reconstsruct. # this is a specific hack fix. A more general fix is to check each dicom to see if the orientation matches the first dicom # but checking EVERY dicom isn't very ideal solution (some datasets might have an ENORMOUS number of dicoms) self.is_non_image = True infer_psd_type(self) mr.adjust_fov_acqmat(self) mr.infer_scan_type(self)
def parse_one(self): """ Composer function, parses all metadata that can be parsed from a single dicom. Called by NIMSData init, if dicom manufacturer is GE Medical Sytems. """ mr.parse_standard_mr_tags(self) self.psd_name = self.getelem(self._hdr, 'PulseSequenceName', str, '').lower() self.psd_iname = self.getelem(self._hdr, 'InternalPulseSequenceName') self.fov_x, self.fov_y = 2 * [ self.getelem(self._hdr, 'ReconstructionDiameter', float) ] self.receive_coil_name = self.getelem(self._hdr, 'ReceiveCoilName') self.mt_offset_hz = self.getelem(self._hdr, 'OffsetFrequency', float) effective_echo_spacing = self.getelem(self._hdr, 'EffectiveEchoSpacing', float) self.effective_echo_spacing = effective_echo_spacing / 1e6 if effective_echo_spacing else None asset_r = self.getelem(self._hdr, 'AssetRFactors', None, [None, None]) if isinstance( asset_r, unicode ) and '\\' in asset_r: # GE Signa HDxt stores asset as string '1\1' asset_r = map( int, asset_r.split('\\')) # reformat to [1, 1] for consistency elif isinstance(asset_r, float): # asset_r can be single item float asset_r = [None, None] self.phase_encode_undersample, self.slice_encode_undersample = asset_r # some very old Ge systems will output dicoms that don't define Locations in Acquition, or define it in a way # that is weird. It may incorrectly label the value type as OB, but not be able to translate the value, resulting # in the MetaExtractor excluding it from the it's output metadata. self.num_slices = self.getelem(self._hdr, 'LocationsInAcquisition', int) self.total_num_slices = self.getelem(self._hdr, 'ImagesInAcquisition', int) self.num_timepoints = self.getelem(self._hdr, 'NumberOfTemporalPositions', int) # slice check could end up wrong, if both total_num_slices and num_slices are None # could force num_slices and total_num_slices into different ORs, to prevent matching if both are None # thus only when they are both defined, AND not equal, can this test pass if (self.total_num_slices or 1) == (self.num_slices or 0): self.total_num_slices = (self.num_slices or 1) * (self.num_timepoints or 1) log.debug('adjusted total_num_slices from %3d to %3d' % (self.num_slices, self.total_num_slices)) # num_slices == 'old' total_num # some localizer don't have header field to indicate the number of slices # per acquisition. If the total_number of slices is set, and the num_timepoints is 1 # then the number of slices should be equal to total number of slices if not self.num_slices and (self.num_timepoints or 1) == 1: self.num_slices = self.total_num_slices prescribed_duration = (self.tr or 0) * (self.num_timepoints or 0) * ( self.num_averages or 1) # FIXME: only works for fMRI, not anatomical if prescribed_duration != 0: self.prescribed_duration = prescribed_duration self.duration = prescribed_duration else: self.prescribed_duration = None self.duration = None dwi_dirs = self.getelem(self._hdr, 'UserData24{#DTIDiffusionDir.,Release10.0&Above}', float) self.dwi_dirs = int(dwi_dirs) if dwi_dirs else None if self.image_type == GEMS_TYPE_ORIG and (self.dwi_dirs or 0) >= 6: self.is_dwi = True self.num_timepoints = 1 if self.image_type == GEMS_TYPE_DERIVED_RFMT: self.is_non_image = True infer_psd_type(self) mr.adjust_fov_acqmat(self) mr.infer_scan_type(self)
def parse_one(self): """ Composer function, parses all metadata that can be parsed from a single dicom. Called by NIMSData init, if dicom manufacturer is GE Medical Sytems. """ mr.parse_standard_mr_tags(self) self.psd_name = self.getelem(self._hdr, 'PulseSequenceName', str, '').lower() self.psd_iname = self.getelem(self._hdr, 'InternalPulseSequenceName') self.fov_x, self.fov_y = 2 * [self.getelem(self._hdr, 'ReconstructionDiameter', float)] self.receive_coil_name = self.getelem(self._hdr, 'ReceiveCoilName') self.mt_offset_hz = self.getelem(self._hdr, 'OffsetFrequency', float) effective_echo_spacing = self.getelem(self._hdr, 'EffectiveEchoSpacing', float) self.effective_echo_spacing = effective_echo_spacing / 1e6 if effective_echo_spacing else None asset_r = self.getelem(self._hdr, 'AssetRFactors', None, [None, None]) if isinstance(asset_r, unicode) and '\\' in asset_r: # GE Signa HDxt stores asset as string '1\1' asset_r = map(int, asset_r.split('\\')) # reformat to [1, 1] for consistency elif isinstance(asset_r, float): # asset_r can be single item float asset_r = [None, None] self.phase_encode_undersample, self.slice_encode_undersample = asset_r # some very old Ge systems will output dicoms that don't define Locations in Acquition, or define it in a way # that is weird. It may incorrectly label the value type as OB, but not be able to translate the value, resulting # in the MetaExtractor excluding it from the it's output metadata. self.num_slices = self.getelem(self._hdr, 'LocationsInAcquisition', int) self.total_num_slices = self.getelem(self._hdr, 'ImagesInAcquisition', int) self.num_timepoints = self.getelem(self._hdr, 'NumberOfTemporalPositions', int) # slice check could end up wrong, if both total_num_slices and num_slices are None # could force num_slices and total_num_slices into different ORs, to prevent matching if both are None # thus only when they are both defined, AND not equal, can this test pass if (self.total_num_slices or 1) == (self.num_slices or 0): self.total_num_slices = (self.num_slices or 1) * (self.num_timepoints or 1) log.debug('adjusted total_num_slices from %3d to %3d' % (self.num_slices, self.total_num_slices)) # num_slices == 'old' total_num # some localizer don't have header field to indicate the number of slices # per acquisition. If the total_number of slices is set, and the num_timepoints is 1 # then the number of slices should be equal to total number of slices if not self.num_slices and (self.num_timepoints or 1) == 1: self.num_slices = self.total_num_slices prescribed_duration = (self.tr or 0) * (self.num_timepoints or 0) * (self.num_averages or 1) # FIXME: only works for fMRI, not anatomical if prescribed_duration != 0: self.prescribed_duration = prescribed_duration self.duration = prescribed_duration else: self.prescribed_duration = None self.duration = None dwi_dirs = self.getelem(self._hdr, 'UserData24{#DTIDiffusionDir.,Release10.0&Above}', float) self.dwi_dirs = int(dwi_dirs) if dwi_dirs else None if self.image_type == GEMS_TYPE_ORIG and (self.dwi_dirs or 0) >= 6: self.is_dwi = True self.num_timepoints = 1 if self.image_type == GEMS_TYPE_DERIVED_RFMT: self.is_non_image = True infer_psd_type(self) mr.adjust_fov_acqmat(self) mr.infer_scan_type(self)