def from_file(cls, fp): """Instantiate a DicomBase instance from a filepath or file-like object. """ dataset = pydicom.dcmread(fp, force=True) return cls(dataset)
def is_anonymised_file(filepath, ignore_private_tags=False): r"""Check whether a DICOM file has been (fully) anonymised. This function specifically checks whether the DICOM file has been anonymised using a PyMedPhys anonymiser. It is very likely that it will return ``False`` for an anonymous DICOM file that was anonymised using a different tool. Parameters ---------- filepath : ``str`` or ``pathlib.Path`` The path to the DICOM file to check for anonymity. ignore_private_tags : ``bool``, optional If set to ``False``, ``is_anonymised_file()`` will return ``False`` if any private (non-standard) DICOM tags exist in the DICOM file. Set to ``True`` to ignore private tags when checking for anonymity. Do so with caution, since private tags may contain identifying information. Defaults to ``False``. Returns ------- is_anonymised : ``bool`` ``True`` if the DICOM dataset read from ``filepath`` has been anonymised, ``False`` otherwise. """ ds = pydicom.dcmread(str(filepath)) return is_anonymised_dataset(ds, ignore_private_tags=ignore_private_tags)
def main(): root = tk.Tk() root.withdraw() path = tk.filedialog.askopenfilename() path = Path(path) path = str(path) ds = pydicom.dcmread(path) mcs = ModulationComplexity(ds=ds) mcs_all = mcs.calcMCS() bc = BeamComplexity(ds=ds) bc_all = bc.calcBeamComplexity() beamNames = mcs_all[0].keys() n = 0 for b in beamNames: beamType = mcs_all[1].get(b) mcs = round(mcs_all[0].get(b), 3) ba = round(bc_all[0].get(b), 1) bi = round(bc_all[1].get(b), 2) bm = round(bc_all[2].get(b), 3) n = n + 1 print(f""" Printing beam complexity report: Beam name: {b} Beam type: {beamType} Modulation Complexity Score: {mcs} Beam Area: {ba} Beam irregularity: {bi} Beam modulation: {bm}""")
def load_dicom_into_deque(filepaths): dicom_datasets_initial_read = [ pydicom.dcmread(filepath, force=True) for filepath in filepaths ] dicom_datasets = convert_datasets_to_deque(dicom_datasets_initial_read) return dicom_datasets
def assign2machine(source_file: str, machine_file: str): """Assign a DICOM RT Plan file to a specific machine. The source file is overwritten to contain the machine of the machine file. Parameters ---------- source_file : str Path to the DICOM RTPlan file that contains the fields/plan desired (e.g. a Winston Lutz set of fields or Varian's default PF files). machine_file : str Path to a DICOM RTPlan file that has the desired machine. This is easily obtained from pushing a plan from the TPS for that specific machine. The file must contain at least one valid field. """ dcm_source = pydicom.dcmread(source_file) dcm_machine = pydicom.dcmread(machine_file) for beam in dcm_source.BeamSequence: beam.TreatmentMachineName = dcm_machine.BeamSequence[ 0].TreatmentMachineName dcm_source.save_as(source_file)
def load_dicom_file(filepath): dicom_dataset = pydicom.dcmread(filepath, force=True, stop_before_pixels=True) return dicom_dataset
def anonymise_file( dicom_filepath, output_filepath=None, delete_original_file=False, anonymise_filename=True, replace_values=True, keywords_to_leave_unchanged=(), delete_private_tags=True, delete_unknown_tags=None, replacement_strategy=None, identifying_keywords=None, ): r"""A simple tool to anonymise a DICOM file. Parameters ---------- dicom_filepath : ``str`` or ``pathlib.Path`` The path to the DICOM file to be anonymised. delete_original_file : ``bool``, optional If `True` and anonymisation completes successfully, then the original DICOM is deleted. Defaults to ``False``. anonymise_filename : ``bool``, optional If ``True``, the DICOM filename is replaced by a filename of the form: "<2 char DICOM modality>.<SOP Instance UID>_Anonymised.dcm". E.g.: "RP.2.16.840.1.113669.[...]_Anonymised.dcm" This ensures that the filename contains no identifying information. If set to ``False``, ``anonymise_file()`` simply appends "_Anonymised" to the original DICOM filename. Defaults to ``True``. replace_values : ``bool``, optional If set to ``True``, DICOM tags will be anonymised using dummy "anonymous" values. This is often required for commercial software to successfully read anonymised DICOM files. If set to ``False``, anonymised tags are simply given empty string values. Defaults to ``True``. keywords_to_leave_unchanged : ``sequence``, optional A sequence of DICOM keywords (corresponding to tags) to exclude from anonymisation. Private and unknown tags can be supplied. Empty by default. delete_private_tags : ``bool``, optional A boolean to flag whether or not to remove all private (non-standard) DICOM tags from the DICOM file. These may also contain identifying information. Defaults to ``True``. delete_unknown_tags : ``bool``, pseudo-optional If left as the default value of ``None`` and ``ds`` contains tags that are not present in PyMedPhys' copy of ``pydicom``'s DICOM dictionary, ``anonymise_dataset()`` will raise an error. The user must then either pass ``True`` or ``False`` to proceed. If set to ``True``, all unrecognised tags that haven't been listed in ``keywords_to_leave_unchanged`` will be deleted. If set to ``False``, these tags are simply ignored. Pass ``False`` with caution, since unrecognised tags may contain identifying information. replacement_strategy: ``dict`` (keys are VR, value is dispatch function), optional If left as the default value of ``None``, the hardcode replacement strategy is used. identifying_keywords: ``list``, optional If left as None, the default values for/list of identifying keywords are used Returns ------- ``str`` The file path of the anonymised file """ dicom_filepath = str(dicom_filepath) ds = pydicom.dcmread(dicom_filepath, force=True) anonymise_dataset( ds=ds, replace_values=replace_values, keywords_to_leave_unchanged=keywords_to_leave_unchanged, delete_private_tags=delete_private_tags, delete_unknown_tags=delete_unknown_tags, copy_dataset=False, replacement_strategy=replacement_strategy, identifying_keywords=identifying_keywords, ) if output_filepath is None: output_filepath = dicom_filepath else: os.makedirs(os.path.split(output_filepath)[0], exist_ok=True) if anonymise_filename: filepath_used = core.create_filename_from_dataset( ds, dirpath=dirname(output_filepath)) else: filepath_used = output_filepath dicom_anon_filepath = core.label_dicom_filepath_as_anonymised( filepath_used) print(f"{dicom_filepath} --> {dicom_anon_filepath}") ds.save_as(dicom_anon_filepath) if delete_original_file: remove_file(dicom_filepath) return dicom_anon_filepath
def _zip_pseudo_fifty_mbytes(file_buffer_list: list, zipfile_path: str, zip_bytes_io=None): """Pseudonymises the contents of the file_buffer_list (list of DICOM files) and places the pseudonymised files in to a zip. Parameters ---------- file_buffer_list : list List of DICOM file buffers from streamlit file_uploader to pseudonymise zipfile_path : str Location to write the zip file so that it can be downloaded. Basename provides default name to use for downloading zip_bytes_io : io.BytesIO, optional An in memory file like object to be used for storing the Zip instead of the zipfile_path. Highly desirable because the zip written to zipfile_path can't be deleted from this module. """ bad_data = False file_count = 0 keywords = pseudonymisation_api.get_default_pseudonymisation_keywords() keywords.remove("PatientSex") strategy = pseudonymisation_api.pseudonymisation_dispatch zip_stream = zipfile_path if zip_bytes_io is not None: zip_stream = zip_bytes_io with ZipFile(zip_stream, mode="w", compression=ZIP_DEFLATED) as myzip: for uploaded_file_buffer in file_buffer_list: file_count += 1 # don't close the buffers. Streamlit provides the user with control over that. # might be appropriate to close the buffers in some circumstances, # but then when the user goes to close the buffer (click x on screen) # there will be an error. try: original_file_name = uploaded_file_buffer.name ds_input: pydicom.FileDataset = pydicom.dcmread( uploaded_file_buffer, force=True) anonymise_dataset( ds_input, delete_private_tags=True, delete_unknown_tags=True, copy_dataset= False, # do the work in place. less memory used and we're disposing shortly anyway identifying_keywords=keywords, replacement_strategy=strategy, ) temp_anon_filepath = build_pseudonymised_file_name(ds_input) in_memory_temp_file = io.BytesIO() anon_filename = pathlib.Path(temp_anon_filepath).name pydicom.dcmwrite(in_memory_temp_file, ds_input) except (KeyError, IOError, ValueError) as e_info: print(e_info) print(f"While processing {original_file_name}") bad_data = True break myzip.writestr( anon_filename, in_memory_temp_file.getvalue(), compress_type=ZIP_DEFLATED, ) in_memory_temp_file.close() return bad_data
def read_dicom3D(direc, i_option): # item = 0 for subdir, dirs, files in os.walk(direc): # pylint: disable = unused-variable k = 0 for file in tqdm(sorted(files)): # print('filename=', file) if os.path.splitext(file)[1] == ".dcm": dataset = pydicom.dcmread(direc + file) if k == 0: ArrayDicom = np.zeros( (dataset.Rows, dataset.Columns, 0), dtype=dataset.pixel_array.dtype, ) tmp_array = dataset.pixel_array if i_option.startswith(("y", "yeah", "yes")): max_val = np.amax(tmp_array) tmp_array = tmp_array / max_val min_val = np.amin(tmp_array) tmp_array = tmp_array - min_val tmp_array = 1 - tmp_array # inverting the range # min_val = np.amin(tmp_array) # normalizing # tmp_array = tmp_array - min_val # tmp_array = tmp_array / (np.amax(tmp_array)) tmp_array = u.norm01(tmp_array) else: # min_val = np.amin(tmp_array) # tmp_array = tmp_array - min_val # tmp_array = tmp_array / (np.amax(tmp_array)) tmp_array = u.norm01(tmp_array) # just normalize ArrayDicom = np.dstack((ArrayDicom, tmp_array)) # print("item thickness [mm]=", dataset.SliceThickness) SID = dataset.RTImageSID dx = 1 / (SID * (1 / dataset.ImagePlanePixelSpacing[0]) / 1000) dy = 1 / (SID * (1 / dataset.ImagePlanePixelSpacing[1]) / 1000) print("pixel spacing row [mm]=", dx) print("pixel spacing col [mm]=", dy) else: tmp_array = dataset.pixel_array if i_option.startswith(("y", "yeah", "yes")): max_val = np.amax(tmp_array) tmp_array = tmp_array / max_val min_val = np.amin(tmp_array) tmp_array = tmp_array - min_val tmp_array = 1 - tmp_array # inverting the range # min_val = np.amin(tmp_array) # normalizing # tmp_array = tmp_array - min_val # tmp_array = tmp_array / (np.amax(tmp_array)) tmp_array = u.norm01(tmp_array) else: # min_val = np.amin(tmp_array) # tmp_array = tmp_array - min_val # tmp_array = tmp_array / (np.amax(tmp_array)) # just normalize tmp_array = u.norm01(tmp_array) ArrayDicom = np.dstack((ArrayDicom, tmp_array)) k = k + 1 xfield, yfield, rotfield = image_analyze(ArrayDicom, i_option) multi_slice_viewer(ArrayDicom, dx, dy) if np.shape(xfield)[2] == 2: fig, peak_figs, junctions_figs = merge_view_vert(xfield, dx, dy) with PdfPages(direc + "jaws_X_report.pdf") as pdf: pdf.savefig(fig) # for i in range(0, len(peak_figs)): for _, f in enumerate(peak_figs): pdf.savefig(f) # for i in range(0, len(junctions_figs)): for _, f in enumerate(junctions_figs): pdf.savefig(f) plt.close() else: print( "X jaws data analysis not completed please verify that you have two X jaws images. For more information see manual." ) if np.shape(yfield)[2] == 4: fig, peak_figs, junctions_figs = merge_view_horz(yfield, dx, dy) # print('peak_figs********************************************************=', len(peak_figs),peak_figs) with PdfPages(direc + "jaws_Y_report.pdf") as pdf: pdf.savefig(fig) # for i in range(0, len(peak_figs)): for _, f in enumerate(peak_figs): pdf.savefig(f) for _, f in enumerate(junctions_figs): pdf.savefig(f) plt.close() else: print( "Y jaws data analysis not completed please verify that you have four Y jaws images. For more information see manual." ) if np.shape(rotfield)[2] == 4: fig, peak_figs, junctions_figs = merge_view_filtrot(rotfield, dx, dy) with PdfPages(direc + "jaws_FR_report.pdf") as pdf: pdf.savefig(fig) for _, f in enumerate(peak_figs): pdf.savefig(f) for _, f in enumerate(junctions_figs): pdf.savefig(f) plt.close() else: print( "Field rotation data analysis not completed please verify that you have four field rotation images. For more information see manual." )
def openPlan(plan): ds = pydicom.dcmread(plan) return ds