def _shrink_file(dicom_file_in, subsample_factor): """ Anonimize a single dicomfile :param dicom_file_in: filepath for input file :param dicom_file_out: filepath for output file :param fields_to_keep: dicom tags to keep """ # Default meta_fields # Required fields according to reference dicom_file_out = dicom_file_in # Load dicom_file_in dicom_in = compressed_dicom.read_file(dicom_file_in) # Create new dicom file # Set new file meta information file_meta = pydicom.dataset.Dataset() for key, value in dicom_in.file_meta.items(): file_meta.add(value) # Create the FileDataset instance (initially no data elements, but file_meta supplied) dicom_out = pydicom.dataset.FileDataset(dicom_file_out, {}, file_meta=file_meta, preamble=b'\0' * 128) # Copy transfer syntax dicom_out.is_little_endian = dicom_in.is_little_endian dicom_out.is_implicit_VR = dicom_in.is_implicit_VR rows = 0 columns = 0 # Add the data elements for field_key, field_value in dicom_in.items(): logging.info(field_key) if field_key == (0x7fe0, 0x0010): pixel_array = dicom_in.pixel_array[::subsample_factor, ::subsample_factor] dicom_out.PixelData = pixel_array.tostring() # = byte array (see pydicom docs) rows = pixel_array.shape[1] columns = pixel_array.shape[0] # noinspection PyPep8Naming dicom_out[0x7fe0, 0x0010].VR = 'OB' else: dicom_out.add(field_value) dicom_out.PixelSpacing[0] *= subsample_factor dicom_out.PixelSpacing[1] *= subsample_factor dicom_out.Rows = rows dicom_out.Columns = columns # Save dicom_file_out # Make sure we have a directory if not os.path.exists(os.path.dirname(dicom_file_out)): logging.info('Decompressing files') # Save the file dicom_out.save_as(dicom_file_out, write_like_original=False)
def _shrink_file(dicom_file_in, subsample_factor): """ Anonimize a single dicomfile :param dicom_file_in: filepath for input file :param dicom_file_out: filepath for output file :param fields_to_keep: dicom tags to keep """ # Default meta_fields # Required fields according to reference dicom_file_out = dicom_file_in # Load dicom_file_in dicom_in = compressed_dicom.read_file(dicom_file_in) # Create new dicom file # Set new file meta information file_meta = dicom.dataset.Dataset() for key, value in dicom_in.file_meta.items(): file_meta.add(value) # Create the FileDataset instance (initially no data elements, but file_meta supplied) dicom_out = dicom.dataset.FileDataset(dicom_file_out, {}, file_meta=file_meta, preamble=b'\0' * 128) # Copy transfer syntax dicom_out.is_little_endian = dicom_in.is_little_endian dicom_out.is_implicit_VR = dicom_in.is_implicit_VR rows = 0 columns = 0 # Add the data elements for field_key, field_value in dicom_in.items(): logging.info(field_key) if field_key == (0x7fe0, 0x0010): pixel_array = dicom_in.pixel_array[::subsample_factor, ::subsample_factor] dicom_out.PixelData = pixel_array.tostring() # = byte array (see pydicom docs) rows = pixel_array.shape[1] columns = pixel_array.shape[0] # noinspection PyPep8Naming dicom_out[0x7fe0, 0x0010].VR = 'OB' else: dicom_out.add(field_value) dicom_out.PixelSpacing[0] *= subsample_factor dicom_out.PixelSpacing[1] *= subsample_factor dicom_out.Rows = rows dicom_out.Columns = columns # Save dicom_file_out # Make sure we have a directory if not os.path.exists(os.path.dirname(dicom_file_out)): logging.info('Decompressing files') # Save the file dicom_out.save_as(dicom_file_out)
def dicom_diff(file1, file2): """ Shows the fields that differ between two DICOM images. Inspired by https://code.google.com/p/pydicom/source/browse/source/dicom/examples/DicomDiff.py """ datasets = compressed_dicom.read_file(file1), compressed_dicom.read_file(file2) rep = [] for dataset in datasets: lines = (str(dataset.file_meta)+"\n"+str(dataset)).split('\n') lines = [line + '\n' for line in lines] # add the newline to the end rep.append(lines) diff = difflib.Differ() for line in diff.compare(rep[0], rep[1]): if (line[0] == '+') or (line[0] == '-'): sys.stdout.write(line)
def dicom_diff(file1, file2): """ Shows the fields that differ between two DICOM images. Inspired by https://code.google.com/p/pydicom/source/browse/source/dicom/examples/DicomDiff.py """ datasets = compressed_dicom.read_file(file1), compressed_dicom.read_file( file2) rep = [] for dataset in datasets: lines = (str(dataset.file_meta) + "\n" + str(dataset)).split('\n') lines = [line + '\n' for line in lines] # add the newline to the end rep.append(lines) diff = difflib.Differ() for line in diff.compare(rep[0], rep[1]): if (line[0] == '+') or (line[0] == '-'): sys.stdout.write(line)
def test_read_file(self): temporary_directory = tempfile.mkdtemp() try: dicom_file = os.path.join(temporary_directory, 'IM-0001-0001-0001.dcm') input_file = os.path.join(test_data.GENERIC_COMPRESSED, 'IM-0001-0001-0001.dcm') shutil.copy(input_file, dicom_file) dicom_headers = compressed_dicom.read_file(dicom_file) pixel_data = dicom_headers.pixel_array self.assertIsNotNone(pixel_data) finally: shutil.rmtree(temporary_directory)
def shrink_multiframe(input_file, output_file=None, slice_count=8, timepoint_count=4): if output_file is None: output_file = input_file # Load dicom_file_in dicom_in = compressed_dicom.read_file(input_file) if _is_multiframe_diffusion_imaging([dicom_in]) or _is_multiframe_4d([dicom_in]): number_of_stack_slices = int(common.get_ss_value(dicom_in[(0x2001, 0x105f)][0][(0x2001, 0x102d)])) number_of_stacks = int(int(dicom_in.NumberOfFrames) / number_of_stack_slices) # We create a numpy array size_x = dicom_in.pixel_array.shape[2] size_y = dicom_in.pixel_array.shape[1] size_t = number_of_stacks frame_info = dicom_in.PerFrameFunctionalGroupsSequence data_4d = numpy.zeros((slice_count * timepoint_count, size_x, size_y), dtype=common.get_numpy_type(dicom_in)) new_frame_info = [None] * slice_count * timepoint_count for index_z in range(0, slice_count): for index_t in range(0, timepoint_count): slice_index = int(size_t * index_z + index_t) new_slice_index = int(timepoint_count * index_z + index_t) z_location = frame_info[slice_index].FrameContentSequence[0].InStackPositionNumber - 1 new_frame_info[new_slice_index] = frame_info[slice_index] logging.info('Importing slice on position %s %s %s' % (slice_index, z_location, index_t)) data_4d[new_slice_index, :, :] = dicom_in.pixel_array[slice_index, :, :] dicom_in.PixelData = data_4d.tostring() common.set_ss_value(dicom_in[(0x2001, 0x105f)][0][(0x2001, 0x102d)], slice_count) setattr(dicom_in, 'NumberOfFrames', slice_count * timepoint_count) setattr(dicom_in, 'PerFrameFunctionalGroupsSequence', new_frame_info) else: # truncate the data dicom_in.PixelData = dicom_in.pixel_array[:slice_count, :, :].tostring() # set number of frames common.set_ss_value(dicom_in[(0x2001, 0x105f)][0][(0x2001, 0x102d)], slice_count) setattr(dicom_in, 'NumberOfFrames', slice_count) # truncate the pre frame groups sequence setattr(dicom_in, 'PerFrameFunctionalGroupsSequence', dicom_in.PerFrameFunctionalGroupsSequence[:slice_count]) # Save the file dicom_in.save_as(output_file)
def _get_first_header(dicom_directory): """ Function to get the first dicom file form a directory and return the header Useful to determine the type of data to convert :param dicom_directory: directory with dicom files """ # looping over all files for root, _, file_names in os.walk(dicom_directory): # go over all the files and try to read the dicom header for file_name in file_names: file_path = os.path.join(root, file_name) # check wither it is a dicom file if not compressed_dicom.is_dicom_file(file_path): continue # read the headers return compressed_dicom.read_file(file_path, stop_before_pixels=True, force=dicom2nifti.settings.pydicom_read_force) # no dicom files found raise ConversionError('NO_DICOM_FILES_FOUND')
def read_dicom_directory(dicom_directory, stop_before_pixels=False): """ Read all dicom files in a given directory (stop before pixels) :type stop_before_pixels: bool :type dicom_directory: six.string_types :param stop_before_pixels: Should we stop reading before the pixeldata (handy if we only want header info) :param dicom_directory: Directory with dicom data :return: List of dicom objects """ dicom_input = [] for root, _, files in os.walk(dicom_directory): for dicom_file in files: file_path = os.path.join(root, dicom_file) if compressed_dicom.is_dicom_file(file_path): dicom_headers = compressed_dicom.read_file(file_path, defer_size=100, stop_before_pixels=stop_before_pixels, force=dicom2nifti.settings.pydicom_read_force) dicom_input.append(dicom_headers) return dicom_input
def read_dicom_directory(dicom_directory, stop_before_pixels=False): """ Read all dicom files in a given directory (stop before pixels) :type stop_before_pixels: bool :type dicom_directory: six.string_types :param stop_before_pixels: Should we stop reading before the pixeldata (handy if we only want header info) :param dicom_directory: Directory with dicom data :return: List of dicom objects """ dicom_input = [] for root, _, files in os.walk(dicom_directory): for dicom_file in files: file_path = os.path.join(root, dicom_file) if compressed_dicom.is_dicom_file(file_path): dicom_headers = compressed_dicom.read_file(file_path, defer_size="1 KB", stop_before_pixels=stop_before_pixels, force=dicom2nifti.settings.pydicom_read_force) if is_valid_imaging_dicom(dicom_headers): dicom_input.append(dicom_headers) return dicom_input
def shrink_multiframe(input_file, output_file=None, slice_count=8, timepoint_count=4): if output_file is None: output_file = input_file # Load dicom_file_in dicom_in = compressed_dicom.read_file(input_file) if _is_multiframe_diffusion_imaging([dicom_in]) or _is_multiframe_4d( [dicom_in]): number_of_stack_slices = int( common.get_ss_value(dicom_in[(0x2001, 0x105f)][0][(0x2001, 0x102d)])) number_of_stacks = int( int(dicom_in.NumberOfFrames) / number_of_stack_slices) # We create a numpy array size_x = dicom_in.pixel_array.shape[2] size_y = dicom_in.pixel_array.shape[1] size_t = number_of_stacks frame_info = dicom_in.PerFrameFunctionalGroupsSequence data_4d = numpy.zeros((slice_count * timepoint_count, size_x, size_y), dtype=common.get_numpy_type(dicom_in)) new_frame_info = [None] * slice_count * timepoint_count for index_z in range(0, slice_count): for index_t in range(0, timepoint_count): slice_index = int(size_t * index_z + index_t) new_slice_index = int(timepoint_count * index_z + index_t) z_location = frame_info[slice_index].FrameContentSequence[ 0].InStackPositionNumber - 1 new_frame_info[new_slice_index] = frame_info[slice_index] logging.info('Importing slice on position %s %s %s' % (slice_index, z_location, index_t)) data_4d[new_slice_index, :, :] = dicom_in.pixel_array[ slice_index, :, :] dicom_in.PixelData = data_4d.tostring() common.set_ss_value(dicom_in[(0x2001, 0x105f)][0][(0x2001, 0x102d)], slice_count) setattr(dicom_in, 'NumberOfFrames', slice_count * timepoint_count) setattr(dicom_in, 'PerFrameFunctionalGroupsSequence', new_frame_info) else: # truncate the data dicom_in.PixelData = dicom_in.pixel_array[:slice_count, :, :].tostring( ) # set number of frames common.set_ss_value(dicom_in[(0x2001, 0x105f)][0][(0x2001, 0x102d)], slice_count) setattr(dicom_in, 'NumberOfFrames', slice_count) # truncate the pre frame groups sequence setattr(dicom_in, 'PerFrameFunctionalGroupsSequence', dicom_in.PerFrameFunctionalGroupsSequence[:slice_count]) # Save the file dicom_in.save_as(output_file)
def test_get_asconv_headers(self): mosaic = compressed_dicom.read_file( os.path.join(test_data.SIEMENS_FMRI, 'IM-0001-0001.dcm')) asconv_headers = convert_siemens._get_asconv_headers(mosaic) assert len(asconv_headers) == 64022
def convert_directory(dicom_directory, output_folder, compression=True, reorient=True): """ This function will order all dicom files by series and order them one by one :param compression: enable or disable gzip compression :param reorient: reorient the dicoms according to LAS orientation :param output_folder: folder to write the nifti files to :param dicom_directory: directory with dicom files """ # sort dicom files by series uid dicom_series = {} for root, _, files in os.walk(dicom_directory): for dicom_file in files: file_path = os.path.join(root, dicom_file) # noinspection PyBroadException try: if compressed_dicom.is_dicom_file(file_path): # read the dicom as fast as possible # (max length for SeriesInstanceUID is 64 so defer_size 100 should be ok) dicom_headers = compressed_dicom.read_file(file_path, defer_size="1 KB", stop_before_pixels=False, force=dicom2nifti.settings.pydicom_read_force) if not _is_valid_imaging_dicom(dicom_headers): logger.info("Skipping: %s" % file_path) continue logger.info("Organizing: %s" % file_path) if dicom_headers.SeriesInstanceUID not in dicom_series: dicom_series[dicom_headers.SeriesInstanceUID] = [] dicom_series[dicom_headers.SeriesInstanceUID].append(dicom_headers) except: # Explicitly capturing all errors here to be able to continue processing all the rest logger.warning("Unable to read: %s" % file_path) traceback.print_exc() # start converting one by one for series_id, dicom_input in iteritems(dicom_series): base_filename = "" # noinspection PyBroadException try: # construct the filename for the nifti base_filename = "" if 'SeriesNumber' in dicom_input[0]: base_filename = _remove_accents('%s' % dicom_input[0].SeriesNumber) if 'SeriesDescription' in dicom_input[0]: base_filename = _remove_accents('%s_%s' % (base_filename, dicom_input[0].SeriesDescription)) elif 'SequenceName' in dicom_input[0]: base_filename = _remove_accents('%s_%s' % (base_filename, dicom_input[0].SequenceName)) elif 'ProtocolName' in dicom_input[0]: base_filename = _remove_accents('%s_%s' % (base_filename, dicom_input[0].ProtocolName)) else: base_filename = _remove_accents(dicom_input[0].SeriesInstanceUID) logger.info('--------------------------------------------') logger.info('Start converting %s' % base_filename) if compression: nifti_file = os.path.join(output_folder, base_filename + '.nii.gz') else: nifti_file = os.path.join(output_folder, base_filename + '.nii') convert_dicom.dicom_array_to_nifti(dicom_input, nifti_file, reorient) gc.collect() except: # Explicitly capturing app exceptions here to be able to continue processing logger.info("Unable to convert: %s" % base_filename) traceback.print_exc()
def _anonymize_file(dicom_file_in, dicom_file_out, fields_to_keep): """ Anonimize a single dicomfile :param dicom_file_in: filepath for input file :param dicom_file_out: filepath for output file :param fields_to_keep: dicom tags to keep """ # Default meta_fields # Required fields according to reference meta_fields = [ 'MediaStorageSOPClassUID', 'MediaStorageSOPInstanceUID', 'ImplementationClassUID' ] # Load dicom_file_in dicom_in = compressed_dicom.read_file(dicom_file_in) # Create new dicom file # Set new file meta information file_meta = pydicom.dataset.Dataset() file_meta.TransferSyntaxUID = pydicom.uid.ExplicitVRLittleEndian for field_key in meta_fields: file_meta.add(dicom_in.file_meta.data_element(field_key)) # Create the FileDataset instance (initially no data elements, but file_meta supplied) dicom_out = pydicom.dataset.FileDataset(dicom_file_out, {}, file_meta=file_meta, preamble=b'\0' * 128) # Copy transfer syntax dicom_out.is_little_endian = dicom_in.is_little_endian dicom_out.is_implicit_VR = dicom_in.is_implicit_VR # Add the data elements for (field_key, field_value) in iteritems(fields_to_keep): logging.info(field_key) if field_key == (0x7fe0, 0x0010): # anonimize the dicom pixeldata random_data = numpy.random.randint( 0, 255, dicom_in.pixel_array.shape).astype(dicom_in.pixel_array.dtype) dicom_out.PixelData = random_data.tostring( ) # = byte array (see pydicom docs) # dicom_out.PixelData = dicom_in.pixel_array.tostring() # = byte array (see pydicom docs) # noinspection PyPep8Naming dicom_out[0x7fe0, 0x0010].VR = 'OB' elif field_value is None: try: if isinstance(field_key, string_types): if field_key in dicom_in: dicom_out.add(dicom_in.data_element(field_key)) else: if dicom_in.get(field_key) is not None: dicom_out.add(dicom_in[field_key]) except KeyError: logging.info('Warning: %s not found' % field_key) else: setattr(dicom_out, field_key, field_value) # Save dicom_file_out # Make sure we have a directory if not os.path.exists(os.path.dirname(dicom_file_out)): logging.info('Decompressing files') # Save the file dicom_out.is_little_endian = True dicom_out.is_implicit_VR = False dicom_out.save_as(dicom_file_out, write_like_original=False)
def test_get_asconv_headers(self): mosaic = compressed_dicom.read_file(os.path.join(test_data.SIEMENS_FMRI, 'IM-0001-0001.dcm')) asconv_headers = convert_siemens._get_asconv_headers(mosaic) assert len(asconv_headers) == 64022
def convert_directory(dicom_directory, output_folder, compression=True, reorient=True): """ This function will order all dicom files by series and order them one by one :param compression: enable or disable gzip compression :param reorient: reorient the dicoms according to LAS orientation :param output_folder: folder to write the nifti files to :param dicom_directory: directory with dicom files """ # sort dicom files by series uid dicom_series = {} for root, _, files in os.walk(dicom_directory): for dicom_file in files: file_path = os.path.join(root, dicom_file) # noinspection PyBroadException try: if compressed_dicom.is_dicom_file(file_path): # read the dicom as fast as possible # (max length for SeriesInstanceUID is 64 so defer_size 100 should be ok) dicom_headers = compressed_dicom.read_file(file_path, defer_size="1 KB", stop_before_pixels=False, force=dicom2nifti.settings.pydicom_read_force) if not _is_valid_imaging_dicom(dicom_headers): logger.info("Skipping: %s" % file_path) continue logger.info("Organizing: %s" % file_path) if dicom_headers.SeriesInstanceUID not in dicom_series: dicom_series[dicom_headers.SeriesInstanceUID] = [] dicom_series[dicom_headers.SeriesInstanceUID].append(dicom_headers) except: # Explicitly capturing all errors here to be able to continue processing all the rest logger.warning("Unable to read: %s" % file_path) traceback.print_exc() # start converting one by one for series_id, dicom_input in dicom_series.items(): base_filename = "" # noinspection PyBroadException try: # construct the filename for the nifti base_filename = "" if 'SeriesNumber' in dicom_input[0]: base_filename = _remove_accents('%s' % dicom_input[0].SeriesNumber) if 'SeriesDescription' in dicom_input[0]: base_filename = _remove_accents('%s_%s' % (base_filename, dicom_input[0].SeriesDescription)) elif 'SequenceName' in dicom_input[0]: base_filename = _remove_accents('%s_%s' % (base_filename, dicom_input[0].SequenceName)) elif 'ProtocolName' in dicom_input[0]: base_filename = _remove_accents('%s_%s' % (base_filename, dicom_input[0].ProtocolName)) else: base_filename = _remove_accents(dicom_input[0].SeriesInstanceUID) logger.info('--------------------------------------------') logger.info('Start converting %s' % base_filename) if compression: nifti_file = os.path.join(output_folder, base_filename + '.nii.gz') else: nifti_file = os.path.join(output_folder, base_filename + '.nii') convert_dicom.dicom_array_to_nifti(dicom_input, nifti_file, reorient) gc.collect() except: # Explicitly capturing app exceptions here to be able to continue processing logger.info("Unable to convert: %s" % base_filename) traceback.print_exc()