def test_validate_sliceincrement(self): validate_slice_increment( sort_dicoms(read_dicom_directory(test_data.GE_ANATOMICAL))) self.assertRaises( ConversionValidationError, validate_slice_increment, sort_dicoms(read_dicom_directory( test_data.FAILING_SLICEINCREMENT)))
def test_is_slice_increment_inconsistent(self): self.assertFalse( is_slice_increment_inconsistent( sort_dicoms(read_dicom_directory(test_data.GE_ANATOMICAL)))) self.assertTrue( is_slice_increment_inconsistent( sort_dicoms( read_dicom_directory(test_data.FAILING_SLICEINCREMENT))))
def _classic_get_grouped_dicoms(dicom_input): """ Search all dicoms in the dicom directory, sort and validate them fast_read = True will only read the headers not the data """ # Loop overall files and build dict # Order all dicom files by InstanceNumber if [d for d in dicom_input if 'InstanceNumber' in d]: dicoms = sorted(dicom_input, key=lambda x: x.InstanceNumber) else: dicoms = common.sort_dicoms(dicom_input) # now group per stack grouped_dicoms = [] # loop over all sorted dicoms stack_position_tag = Tag( 0x0020, 0x0012) # in this case it is the acquisition number for index in range(0, len(dicoms)): dicom_ = dicoms[index] if stack_position_tag not in dicom_: stack_index = 0 else: stack_index = dicom_[stack_position_tag].value - 1 while len(grouped_dicoms) <= stack_index: grouped_dicoms.append([]) grouped_dicoms[stack_index].append(dicom_) return grouped_dicoms
def _get_grouped_dicoms(dicom_input): """ Search all dicoms in the dicom directory, sort and validate them fast_read = True will only read the headers not the data """ # if all dicoms have an instance number try sorting by instance number else by position if [d for d in dicom_input if 'InstanceNumber' in d]: dicoms = sorted(dicom_input, key=lambda x: x.InstanceNumber) else: dicoms = common.sort_dicoms(dicom_input) # now group per stack grouped_dicoms = [[]] # list with first element a list timepoint_index = 0 previous_stack_position = -1 # loop over all sorted dicoms stack_position_tag = Tag(0x2001, 0x100a) # put this there as this is a slow step and used a lot for index in range(0, len(dicoms)): dicom_ = dicoms[index] stack_position = 0 if stack_position_tag in dicom_: stack_position = common.get_is_value(dicom_[stack_position_tag]) if previous_stack_position == stack_position: # if the stack number is the same we move to the next timepoint timepoint_index += 1 if len(grouped_dicoms) <= timepoint_index: grouped_dicoms.append([]) else: # if it changes move back to the first timepoint timepoint_index = 0 grouped_dicoms[timepoint_index].append(dicom_) previous_stack_position = stack_position return grouped_dicoms
def _classic_get_grouped_dicoms(dicom_input): """ Search all dicoms in the dicom directory, sort and validate them fast_read = True will only read the headers not the data """ # Loop overall files and build dict # Order all dicom files by InstanceNumber if [d for d in dicom_input if 'InstanceNumber' in d]: dicoms = sorted(dicom_input, key=lambda x: x.InstanceNumber) else: dicoms = common.sort_dicoms(dicom_input) # now group per stack grouped_dicoms = [] # loop over all sorted dicoms stack_position_tag = Tag(0x0020, 0x0012) # in this case it is the acquisition number for index in range(0, len(dicoms)): dicom_ = dicoms[index] if stack_position_tag not in dicom_: stack_index = 0 else: stack_index = dicom_[stack_position_tag].value - 1 while len(grouped_dicoms) <= stack_index: grouped_dicoms.append([]) grouped_dicoms[stack_index].append(dicom_) return grouped_dicoms
def dicom_to_nifti(dicom_input, output_file): """ This function will convert an anatomical dicom series to a nifti Examples: See unit test :param output_file: filepath to the output nifti :param dicom_input: directory with the dicom files for a single scan, or list of read in dicoms """ if len(dicom_input) <= 0: raise ConversionError('NO_DICOM_FILES_FOUND') # remove duplicate slices based on position and data dicom_input = _remove_duplicate_slices(dicom_input) # remove localizers based on image type dicom_input = _remove_localizers_by_imagetype(dicom_input) if settings.validate_slicecount: # remove_localizers based on image orientation (only valid if slicecount is validated) dicom_input = _remove_localizers_by_orientation(dicom_input) # validate all the dicom files for correct orientations common.validate_slicecount(dicom_input) if settings.validate_orientation: # validate that all slices have the same orientation common.validate_orientation(dicom_input) if settings.validate_orthogonal: # validate that we have an orthogonal image (to detect gantry tilting etc) common.validate_orthogonal(dicom_input) # sort the dicoms dicom_input = common.sort_dicoms(dicom_input) if settings.validate_sliceincrement: # validate that all slices have a consistent slice increment common.validate_sliceincrement(dicom_input) # Get data; originally z,y,x, transposed to x,y,z data = common.get_volume_pixeldata(dicom_input) affine = common.create_affine(dicom_input) # Convert to nifti nii_image = nibabel.Nifti1Image(data, affine) # Set TR and TE if available if Tag(0x0018, 0x0081) in dicom_input[0] and Tag(0x0018, 0x0081) in dicom_input[0]: common.set_tr_te(nii_image, float(dicom_input[0].RepetitionTime), float(dicom_input[0].EchoTime)) # Save to disk if output_file is not None: logger.info('Saving nifti to disk %s' % output_file) nii_image.to_filename(output_file) return {'NII_FILE': output_file, 'NII': nii_image}
def dicom_to_nifti(dicom_input, output_file): """ This function will convert an anatomical dicom series to a nifti Examples: See unit test :param output_file: filepath to the output nifti :param dicom_input: directory with the dicom files for a single scan, or list of read in dicoms """ if len(dicom_input) <= 0: raise ConversionError('NO_DICOM_FILES_FOUND') # remove duplicate slices based on position and data dicom_input = remove_duplicate_slices(dicom_input) # remove localizers based on image type dicom_input = remove_localizers_by_imagetype(dicom_input) # if no dicoms remain we should raise exception if len(dicom_input) < 1: raise ConversionValidationError('TOO_FEW_SLICES/LOCALIZER') if settings.validate_slicecount: common.validate_slicecount(dicom_input) # remove_localizers based on image orientation (only valid if slicecount is validated) dicom_input = remove_localizers_by_orientation(dicom_input) # validate all the dicom files for correct orientations common.validate_slicecount(dicom_input) if settings.validate_orientation: # validate that all slices have the same orientation common.validate_orientation(dicom_input) if settings.validate_orthogonal: # validate that we have an orthogonal image (to detect gantry tilting etc) common.validate_orthogonal(dicom_input) # sort the dicoms dicom_input = common.sort_dicoms(dicom_input) # validate slice increment inconsistent slice_increment_inconsistent = False if settings.validate_slice_increment: # validate that all slices have a consistent slice increment common.validate_slice_increment(dicom_input) elif common.is_slice_increment_inconsistent(dicom_input): slice_increment_inconsistent = True if settings.validate_instance_number: # validate that all slices have a consistent instance_number common.validate_instance_number(dicom_input) # if inconsistent increment and we allow resampling then do the resampling based conversion to maintain the correct geometric shape if slice_increment_inconsistent and settings.resample: nii_image, max_slice_increment = _convert_slice_incement_inconsistencies(dicom_input) # do the normal conversion else: # Get data; originally z,y,x, transposed to x,y,z data = common.get_volume_pixeldata(dicom_input) affine, max_slice_increment = common.create_affine(dicom_input) # Convert to nifti nii_image = nibabel.Nifti1Image(data.squeeze(), affine) # Set TR and TE if available if Tag(0x0018, 0x0080) in dicom_input[0] and Tag(0x0018, 0x0081) in dicom_input[0]: common.set_tr_te(nii_image, float(dicom_input[0].RepetitionTime), float(dicom_input[0].EchoTime)) # Save to disk if output_file is not None: logger.info('Saving nifti to disk %s' % output_file) nii_image.header.set_slope_inter(1, 0) nii_image.header.set_xyzt_units(2) # set units for xyz (leave t as unknown) nii_image.to_filename(output_file) return {'NII_FILE': output_file, 'NII': nii_image, 'MAX_SLICE_INCREMENT': max_slice_increment}
def test_validate_sliceincrement(self): validate_slice_increment(sort_dicoms(read_dicom_directory(test_data.GE_ANATOMICAL))) self.assertRaises(ConversionValidationError, validate_slice_increment, sort_dicoms(read_dicom_directory(test_data.FAILING_SLICEINCREMENT)))
def dicom_to_nifti(dicom_input, output_file): """ This function will convert an anatomical dicom series to a nifti Examples: See unit test :param output_file: filepath to the output nifti :param dicom_input: directory with the dicom files for a single scan, or list of read in dicoms """ if len(dicom_input) <= 0: raise ConversionError('NO_DICOM_FILES_FOUND') # remove duplicate slices based on position and data dicom_input = _remove_duplicate_slices(dicom_input) # remove localizers based on image type dicom_input = _remove_localizers_by_imagetype(dicom_input) if settings.validate_slicecount: # remove_localizers based on image orientation (only valid if slicecount is validated) dicom_input = _remove_localizers_by_orientation(dicom_input) # validate all the dicom files for correct orientations common.validate_slicecount(dicom_input) if settings.validate_orientation: # validate that all slices have the same orientation common.validate_orientation(dicom_input) if settings.validate_orthogonal: # validate that we have an orthogonal image (to detect gantry tilting etc) common.validate_orthogonal(dicom_input) # sort the dicoms dicom_input = common.sort_dicoms(dicom_input) # validate slice increment inconsistent slice_increment_inconsistent = False if settings.validate_slice_increment: # validate that all slices have a consistent slice increment common.validate_slice_increment(dicom_input) elif common.is_slice_increment_inconsistent(dicom_input): slice_increment_inconsistent = True # if inconsistent increment and we allow resampling then do the resampling based conversion to maintain the correct geometric shape if slice_increment_inconsistent and settings.resample: nii_image, max_slice_increment = _convert_slice_incement_inconsistencies(dicom_input) # do the normal conversion else: # Get data; originally z,y,x, transposed to x,y,z data = common.get_volume_pixeldata(dicom_input) affine, max_slice_increment = common.create_affine(dicom_input) # Convert to nifti nii_image = nibabel.Nifti1Image(data, affine) # Set TR and TE if available if Tag(0x0018, 0x0081) in dicom_input[0] and Tag(0x0018, 0x0081) in dicom_input[0]: common.set_tr_te(nii_image, float(dicom_input[0].RepetitionTime), float(dicom_input[0].EchoTime)) # Save to disk if output_file is not None: logger.info('Saving nifti to disk %s' % output_file) nii_image.to_filename(output_file) return {'NII_FILE': output_file, 'NII': nii_image, 'MAX_SLICE_INCREMENT': max_slice_increment}