def reveal_anonymized_files(self, directory): ph.create_directory(directory) filenames_revealed = [] for i in range(0, len(self._filenames)): basename_anonymized = os.path.basename(self._filenames[i]) filename_anonymized = ph.strip_filename_extension( basename_anonymized)[0] try: basename_revealed = self._dictionary[basename_anonymized] except KeyError: raise IOError( "Dictionary does not match given (anonymized) filenames") filename_revealed = "%s_%s" % (filename_anonymized, basename_revealed) # filename_anonymized = self._identifiers[i] + filename_extension # filename_revealed = self._identifiers[i] + "_" + \ # self._dictionary[self._identifiers[i]] + filename_extension # filename_revealed = re.sub("_masked_srr", "", filename_revealed) # path_to_file_anon = os.path.join(directory, filename_anonymized) path_to_file_reve = os.path.join(directory, filename_revealed) # if not os.path.isfile(path_to_file_anon): # print("%s: Nothing to reveal" % (filename_anonymized)) cmd = "cp -p " cmd += self._filenames[i] + " " cmd += path_to_file_reve + " " # print(cmd) ph.execute_command(cmd) filenames_revealed.append(filename_revealed) return filenames_revealed
def read_transform(path_to_file, inverse=0, nii_as_nib=0, as_itk=0): if not ph.file_exists(path_to_file): raise IOError("Transform file '%s' not found" % path_to_file) extension = ph.strip_filename_extension(path_to_file)[1] if extension not in ALLOWED_TRANSFORMS and \ extension not in ALLOWED_TRANSFORMS_DISPLACEMENTS: raise IOError("Transform file extension must be of type " "%s (transformation) or %s (displacements)" % (", ".join(ALLOWED_TRANSFORMS), ", ".join(ALLOWED_TRANSFORMS_DISPLACEMENTS))) if extension in ALLOWED_TRANSFORMS: if as_itk: tranform_sitk = sitk.read_transform_itk(path_to_file, inverse=inverse) else: transform_sitk = sitkh.read_transform_sitk(path_to_file, inverse=inverse) else: # Used for sitk_to_nreg conversion only if nii_as_nib: displacement_sitk = nib.load(path_to_file) return displacement_sitk else: displacement_sitk = sitk.ReadImage(path_to_file, sitk.sitkVectorFloat64) transform_sitk = sitk.DisplacementFieldTransform( sitk.Image(displacement_sitk)) if inverse: # May throw RuntimeError transform_sitk = transform_sitk.GetInverse() return transform_sitk
def read_transform_nreg(path_to_file): if not ph.file_exists(path_to_file): raise IOError("NiftyReg transform file '%s' not found" % path_to_file) extension = ph.strip_filename_extension(path_to_file)[1] if extension not in ALLOWED_TRANSFORMS and \ extension not in ALLOWED_TRANSFORMS_DISPLACEMENTS: raise IOError("NiftyReg transform file extension must be of type " "%s (reg_aladin) or %s (reg_f3d displacement)" % (", ".join(ALLOWED_TRANSFORMS), ", ".join(ALLOWED_TRANSFORMS_DISPLACEMENTS))) if extension in ALLOWED_TRANSFORMS: transform_nreg = np.loadtxt(path_to_file) else: transform_nreg = nib.load(path_to_file) # check that image is a NiftyReg displacement field header = transform_nreg.get_header() if int(header['intent_p1']) != 1 or \ int(header['intent_p2']) != 0 or \ int(header['intent_p3']) != 0 or \ int(header['intent_code']) != 1007: raise IOError("Provided image must represent a NiftyReg " "displacement field") return transform_nreg
def read_landmarks(path_to_file): if not ph.file_exists(path_to_file): raise IOError("Landmark file '%s' not found" % path_to_file) extension = ph.strip_filename_extension(path_to_file)[1] if extension not in ALLOWED_LANDMARKS: raise IOError("Landmark file extension must be of type %s " % ", or ".join(ALLOWED_LANDMARKS)) return np.loadtxt(path_to_file)
def read_transform_flirt(path_to_file): if not ph.file_exists(path_to_file): raise IOError("FLIRT transform file '%s' not found" % path_to_file) extension = ph.strip_filename_extension(path_to_file)[1] if extension not in ALLOWED_TRANSFORMS: raise IOError("FLIRT transform file extension must be of type %s" % ", or ".join(ALLOWED_TRANSFORMS)) return np.loadtxt(path_to_file)
def save_landmarks_to_image(self, path_to_file): if self._landmarks_image_space is None: raise RuntimeError("Execute 'run' first to estimate landmarks") ph.print_info("Save landmarks to image '%s' ... " % path_to_file, newline=False) # read original image image_label_sitk = sitk.ReadImage(self._path_to_image_label) image_label_nda = sitk.GetArrayFromImage(image_label_sitk) * 0 # convert to integer voxels image_label_nda = self._get_array_with_landmarks( image_label_sitk.GetSize()[::-1], self._landmarks_voxel_space) # landmarks_voxel_space = self._landmarks_voxel_space.astype('int') # for i in range(landmarks_voxel_space.shape[0]): # image_label_nda[landmarks_voxel_space[i, 2], # landmarks_voxel_space[i, 1], # landmarks_voxel_space[i, 0]] = 1 image_landmarks_sitk = sitk.GetImageFromArray(image_label_nda) image_landmarks_sitk.CopyInformation(image_label_sitk) sitkh.write_nifti_image_sitk(image_landmarks_sitk, path_to_file) print("done") # show landmark estimate if self._verbose: # find bounding box for "zoomed in" visualization ran_x, ran_y, ran_z = self._get_bounding_box(image_label_nda) # get zoomed-in image mask image_label_nda_show = image_label_nda[ran_x[0]:ran_x[1], ran_y[0]:ran_y[1], ran_z[0]:ran_z[1]] landmarks_nda = self._get_array_with_landmarks( image_label_nda.shape, self._landmarks_voxel_space) show_mask_sitk = sitk.GetImageFromArray(image_label_nda_show) # get zoomed-in landmark estimate (dilated for visualization) landmarks_nda_show = landmarks_nda[ran_x[0]:ran_x[1], ran_y[0]:ran_y[1], ran_z[0]:ran_z[1]] landmarks_nda_show += scipy.ndimage.morphology.binary_dilation( landmarks_nda_show, iterations=10) show_landmarks_sitk = sitk.GetImageFromArray(landmarks_nda_show) sitkh.show_sitk_image(show_mask_sitk, segmentation=show_landmarks_sitk, label=os.path.basename( ph.strip_filename_extension( self._path_to_image_label)[0]))
def write_landmarks(landmarks_nda, path_to_file, verbose=0): extension = ph.strip_filename_extension(path_to_file)[1] if extension not in ALLOWED_LANDMARKS: raise IOError("Landmark file extension must be of type %s " % ", or ".join(ALLOWED_LANDMARKS)) ph.write_array_to_file(path_to_file, landmarks_nda, delimiter=" ", access_mode="w", verbose=verbose)
def write_image(image_sitk, path_to_file, verbose=0): extension = ph.strip_filename_extension(path_to_file)[1] if extension not in ALLOWED_IMAGES: raise IOError("Image file extension must be of type %s " % ", or ".join(ALLOWED_IMAGES)) if isinstance(image_sitk, sitk.Image): sitkh.write_nifti_image_sitk(image_sitk=image_sitk, path_to_file=path_to_file, verbose=verbose) else: sitkh.write_nifti_image_itk(image_itk=image_sitk, path_to_file=path_to_file, verbose=verbose)
def write_vector_image(vector_image_sitk, path_to_file, verbose=0): extension = ph.strip_filename_extension(path_to_file)[1] if extension not in ALLOWED_IMAGES: raise IOError("Image file extension must be of type %s " % ", or ".join(ALLOWED_IMAGES)) if isinstance(vector_image_sitk, sitk.Image): sitkh.write_sitk_vector_image( vector_image_sitk, path_to_file, verbose=verbose, ) else: raise ValueError("Only implemented for SimpleITK images")
def write_transform(transform_sitk, path_to_file, verbose=0): extension = ph.strip_filename_extension(path_to_file)[1] if extension not in ALLOWED_TRANSFORMS and \ extension not in ALLOWED_TRANSFORMS_DISPLACEMENTS: raise IOError("Transform file extension must be of type " "%s (transformation) or %s (displacements)" % (", ".join(ALLOWED_TRANSFORMS), ", ".join(ALLOWED_TRANSFORMS_DISPLACEMENTS))) if extension in ALLOWED_TRANSFORMS: if isinstance(transform_sitk, sitk.Image): raise IOError("Cannot convert displacement field (%s) to " "transform (%s)" % ( ", ".join(ALLOWED_TRANSFORMS_DISPLACEMENTS), ", ".join(ALLOWED_TRANSFORMS), )) if isinstance(transform_sitk, sitk.Transform): ph.create_directory(os.path.dirname(path_to_file)) sitk.WriteTransform(transform_sitk, path_to_file) if verbose: ph.print_info("Transform written to '%s'" % path_to_file) elif isinstance(transform_sitk, np.ndarray): ph.write_array_to_file(path_to_file, transform_sitk, delimiter=" ", access_mode="w", verbose=verbose) else: raise IOError("Transform must be of type " "sitk.Transform or np.ndarray") else: if isinstance(transform_sitk, sitk.Transform): raise IOError("Cannot convert transform (%s) to " "displacement field (%s)" % ( ", ".join(ALLOWED_TRANSFORMS), ", ".join(ALLOWED_TRANSFORMS_DISPLACEMENTS), )) elif isinstance(transform_sitk, sitk.Image): sitkh.write_nifti_image_sitk(image_sitk=transform_sitk, path_to_file=path_to_file, verbose=verbose) elif isinstance(transform_sitk, nib.nifti1.Nifti1Image): ph.create_directory(os.path.dirname(path_to_file)) nib.save(transform_sitk, path_to_file) else: raise IOError("Transform must be of type " "sitk.Image or nibabel.nifti1.Nifti1Image")
def read_landmarks(path_to_file): if not ph.file_exists(path_to_file): raise IOError("Landmark file '%s' not found" % path_to_file) extension = ph.strip_filename_extension(path_to_file)[1] if extension not in ALLOWED_LANDMARKS: raise IOError("Landmark file extension must be of type %s " % ", or ".join(ALLOWED_LANDMARKS)) nda = np.loadtxt(path_to_file) if nda.shape[1] not in [2, 3]: raise IOError("Landmark array file must be of shape N x dim, " "with dim either 2 or 3.") return nda
def read_image(path_to_file, as_itk=0): if not ph.file_exists(path_to_file): raise IOError("Image file '%s' not found" % path_to_file) extension = ph.strip_filename_extension(path_to_file)[1] if extension not in ALLOWED_IMAGES: raise IOError("Image file extension must be of type %s " % ", or ".join(ALLOWED_IMAGES)) # Read as itk.Image object if as_itk: image = itk.imread(path_to_file) # Read as sitk.Image object else: image = sitk.ReadImage(path_to_file) return image
def generate_randomized_dictionary(self): self._dictionary = {} if len(self._filenames) is not len(self._identifiers): raise ValueError("Length of filenames does not match identifiers") # Shuffle identifiers random.shuffle(self._identifiers) # Create dictionary for i in range(0, len(self._filenames)): basename = os.path.basename(os.path.basename(self._filenames[i])) filename, ext = ph.strip_filename_extension(basename) # Update identifier including the prefix self._identifiers[i] = "%s%s.%s" % (self._prefix_identifiers, self._identifiers[i], ext) # Create dictionary self._dictionary[self._identifiers[i]] = basename
def write_dictionary(self, path_to_file, filename_backup=None, verbose=False): directory = os.path.dirname((path_to_file)) filename, ext = ph.strip_filename_extension( os.path.basename(path_to_file)) ph.create_directory(directory) # Write backup file (human readable) if filename_backup is None: path_to_file_backup = os.path.join( directory, "%s_backup_human_readable.txt" % filename) # Save randomized dictionary f = open(path_to_file, 'wb') cPickle.dump(self._dictionary, f, protocol=cPickle.HIGHEST_PROTOCOL) f.close() date = ph.get_current_date() time = ph.get_current_time() file_handle = open(path_to_file_backup, "w") text = "## Randomized Dictionary " + date + " " + time + "\n" file_handle.write(text) file_handle.close() # Print in an alphabetical order keys = sorted(self._dictionary.keys()) for i in range(0, len(self._filenames)): file_handle = open(path_to_file_backup, "a") text = keys[i] + " : " + self._dictionary[keys[i]] + "\n" file_handle.write(text) file_handle.close() if verbose: print("\t%s : %s" % (keys[i], self._dictionary[keys[i]])) ph.print_info("Anonymization dictionary written to '%s'" % path_to_file)
def main(): parser = argparse.ArgumentParser( description="Script to anonymize multiple files. " "This usually comes in three steps: " "1) --create-dictionary " "2) --anonymize-files " "3) --reveal-files (after assessment)") parser.add_argument( '-f', '--filenames', required=True, type=str, nargs="+", help="Path to filenames", ) parser.add_argument( '-d', '--dictionary', required=True, type=str, help="Path to dictionary that shall be used for anonymization (*.o). " "Can be computed using the '--create-dictionary' flag if not available yet.", ) parser.add_argument( '-o', '--dir-output', required=False, type=str, help="Path to output directory for whatever anonymization step. ", ) parser.add_argument( "-p", "--prefix", help="Prefix used when anonymization dictionary is created", type=str, default="anonymized_", ) # Options for anonymization runs parser.add_argument( "--create-dictionary", help="Create a dictionary that shall be used for anonymization. " "Typically, this is the first step.", action='store_true') parser.add_argument("--anonymize-files", help="Anonymize files based on a given dictionary. " "Typically, this is the second step.", action='store_true') parser.add_argument( "--reveal-files", help="Reveal anonymized files. " "Typically, this is the third step (after assessment).", action='store_true') args = parser.parse_args() data_anonymizer = da.DataAnonymizer( filenames=args.filenames, prefix_identifiers=args.prefix, ) if ph.strip_filename_extension(args.dictionary)[1] != "o": raise IOError("--dictionary must point to an *.o file") if args.create_dictionary: data_anonymizer.generate_identifiers() data_anonymizer.generate_randomized_dictionary() data_anonymizer.write_dictionary(args.dictionary) if args.anonymize_files: if args.dir_output is None: raise IOError("--dir-output must be provided") data_anonymizer.read_dictionary(args.dictionary) data_anonymizer.anonymize_files(args.dir_output) if args.reveal_files: if args.dir_output is None: raise IOError("--dir-output must be provided") data_anonymizer.read_dictionary(args.dictionary) data_anonymizer.reveal_anonymized_files(args.dir_output) return 0