def main(): input_parser = InputArgparser(description="Convert NIfTI to DICOM image", ) input_parser.add_filename(required=True) input_parser.add_option( option_string="--template", type=str, required=True, help="Template DICOM to extract relevant DICOM tags.", ) input_parser.add_dir_output(required=True) input_parser.add_label( help="Label used for series description of DICOM output.", default="SRR_NiftyMIC") input_parser.add_argument( "--volume", "-volume", action='store_true', help="If given, the output DICOM file is combined as 3D volume") args = input_parser.parse_args() input_parser.print_arguments(args) # Prepare for final DICOM output ph.create_directory(args.dir_output) if args.volume: dir_output_2d_slices = os.path.join(DIR_TMP, "dicom_slices") else: dir_output_2d_slices = os.path.join(args.dir_output, args.label) ph.create_directory(dir_output_2d_slices, delete_files=True) # read NiftyMIC version (if available) data_reader = dr.ImageHeaderReader(args.filename) data_reader.read_data() niftymic_version = data_reader.get_niftymic_version() if niftymic_version is None: niftymic_version = "NiftyMIC" else: niftymic_version = "NiftyMIC-v%s" % niftymic_version # Create set of 2D DICOM slices from 3D NIfTI image # (correct image orientation!) ph.print_title("Create set of 2D DICOM slices from 3D NIfTI image") cmd_args = ["nifti2dicom"] cmd_args.append("-i '%s'" % args.filename) cmd_args.append("-o '%s'" % dir_output_2d_slices) cmd_args.append("-d '%s'" % args.template) cmd_args.append("--prefix ''") cmd_args.append("--seriesdescription '%s'" % args.label) cmd_args.append("--accessionnumber '%s'" % ACCESSION_NUMBER) cmd_args.append("--seriesnumber '%s'" % SERIES_NUMBER) cmd_args.append("--institutionname '%s'" % IMAGE_COMMENTS) # Overwrite default "nifti2dicom" tags which would be added otherwise # (no deletion/update with empty '' sufficient to overwrite them) cmd_args.append("--manufacturersmodelname '%s'" % "NiftyMIC") cmd_args.append("--protocolname '%s'" % niftymic_version) cmd_args.append("-y") ph.execute_command(" ".join(cmd_args)) if args.volume: path_to_output = os.path.join(args.dir_output, "%s.dcm" % args.label) # Combine set of 2D DICOM slices to form 3D DICOM image # (image orientation stays correct) ph.print_title("Combine set of 2D DICOM slices to form 3D DICOM image") cmd_args = ["medcon"] cmd_args.append("-f '%s'/*.dcm" % dir_output_2d_slices) cmd_args.append("-o '%s'" % path_to_output) cmd_args.append("-c dicom") cmd_args.append("-stack3d") cmd_args.append("-n") cmd_args.append("-qc") cmd_args.append("-w") ph.execute_command(" ".join(cmd_args)) # Update all relevant DICOM tags accordingly ph.print_title("Update all relevant DICOM tags accordingly") print("") dataset_template = pydicom.dcmread(args.template) dataset = pydicom.dcmread(path_to_output) # Copy tags from template (to guarantee grouping with original data) update_dicom_tags = {} for tag in COPY_DICOM_TAGS: try: update_dicom_tags[tag] = getattr(dataset_template, tag) except: update_dicom_tags[tag] = "" # Additional tags update_dicom_tags["SeriesDescription"] = args.label update_dicom_tags["InstitutionName"] = institution_name update_dicom_tags["ImageComments"] = IMAGE_COMMENTS update_dicom_tags["AccessionNumber"] = ACCESSION_NUMBER update_dicom_tags["SeriesNumber"] = SERIES_NUMBER for tag in sorted(update_dicom_tags.keys()): value = update_dicom_tags[tag] setattr(dataset, tag, value) ph.print_info("%s: '%s'" % (tag, value)) dataset.save_as(path_to_output) print("") ph.print_info("3D DICOM image written to '%s'" % path_to_output) else: ph.print_info("DICOM images written to '%s'" % dir_output_2d_slices) return 0
def main(): time_start = ph.start_timing() np.set_printoptions(precision=3) input_parser = InputArgparser( description="Perform Bias Field correction using N4ITK.", ) input_parser.add_filename(required=True) input_parser.add_output(required=True) input_parser.add_filename_mask() input_parser.add_option( option_string="--convergence-threshold", type=float, help="Specify the convergence threshold.", default=1e-6, ) input_parser.add_option( option_string="--spline-order", type=int, help="Specify the spline order defining the bias field estimate.", default=3, ) input_parser.add_option( option_string="--wiener-filter-noise", type=float, help="Specify the noise estimate defining the Wiener filter.", default=0.11, ) input_parser.add_option( option_string="--bias-field-fwhm", type=float, help="Specify the full width at half maximum parameter characterizing " "the width of the Gaussian deconvolution.", default=0.15, ) input_parser.add_log_config(default=1) input_parser.add_verbose(default=0) args = input_parser.parse_args() input_parser.print_arguments(args) if np.alltrue([not args.output.endswith(t) for t in ALLOWED_EXTENSIONS]): raise ValueError( "output filename invalid; allowed extensions are: %s" % ", ".join(ALLOWED_EXTENSIONS)) if args.log_config: input_parser.log_config(os.path.abspath(__file__)) # Read data stack = st.Stack.from_filename( file_path=args.filename, file_path_mask=args.filename_mask, extract_slices=False, ) # Perform Bias Field Correction # ph.print_title("Perform Bias Field Correction") bias_field_corrector = n4itk.N4BiasFieldCorrection( stack=stack, use_mask=True if args.filename_mask is not None else False, convergence_threshold=args.convergence_threshold, spline_order=args.spline_order, wiener_filter_noise=args.wiener_filter_noise, bias_field_fwhm=args.bias_field_fwhm, ) ph.print_info("N4ITK Bias Field Correction ... ", newline=False) bias_field_corrector.run_bias_field_correction() stack_corrected = bias_field_corrector.get_bias_field_corrected_stack() print("done") dw.DataWriter.write_image(stack_corrected.sitk, args.output) elapsed_time = ph.stop_timing(time_start) if args.verbose: ph.show_niftis([args.filename, args.output]) ph.print_title("Summary") exe_file_info = os.path.basename(os.path.abspath(__file__)).split(".")[0] print("%s | Computational Time for Bias Field Correction: %s" % (exe_file_info, elapsed_time)) return 0