def main():

    time_start = ph.start_timing()

    np.set_printoptions(precision=3)

    input_parser = InputArgparser(
        description="Run reconstruction pipeline including "
        "(i) bias field correction, "
        "(ii) volumetric reconstruction in subject space, "
        "and (iii) volumetric reconstruction in template space.", )
    input_parser.add_filenames(required=True)
    input_parser.add_filenames_masks(required=True)
    input_parser.add_target_stack(required=False)
    input_parser.add_suffix_mask(default="''")
    input_parser.add_dir_output(required=True)
    input_parser.add_alpha(default=0.01)
    input_parser.add_verbose(default=0)
    input_parser.add_gestational_age(required=False)
    input_parser.add_prefix_output(default="")
    input_parser.add_search_angle(default=180)
    input_parser.add_multiresolution(default=0)
    input_parser.add_log_config(default=1)
    input_parser.add_isotropic_resolution()
    input_parser.add_reference()
    input_parser.add_reference_mask()
    input_parser.add_bias_field_correction(default=1)
    input_parser.add_intensity_correction(default=1)
    input_parser.add_iter_max(default=10)
    input_parser.add_two_step_cycles(default=3)
    input_parser.add_option(
        option_string="--run-bias-field-correction",
        type=int,
        help="Turn on/off bias field correction. "
        "If off, it is assumed that this step was already performed",
        default=1)
    input_parser.add_option(
        option_string="--run-recon-subject-space",
        type=int,
        help="Turn on/off reconstruction in subject space. "
        "If off, it is assumed that this step was already performed",
        default=1)
    input_parser.add_option(
        option_string="--run-recon-template-space",
        type=int,
        help="Turn on/off reconstruction in template space. "
        "If off, it is assumed that this step was already performed",
        default=1)
    input_parser.add_option(
        option_string="--run-data-vs-simulated-data",
        type=int,
        help="Turn on/off comparison of data vs data simulated from the "
        "obtained volumetric reconstruction. "
        "If off, it is assumed that this step was already performed",
        default=0)
    input_parser.add_option(
        option_string="--initial-transform",
        type=str,
        help="Set initial transform to be used for register_image.",
        default=None)
    input_parser.add_outlier_rejection(default=1)
    input_parser.add_argument(
        "--sda",
        "-sda",
        action='store_true',
        help="If given, the volume is reconstructed using "
        "Scattered Data Approximation (Vercauteren et al., 2006). "
        "--alpha is considered the value for the standard deviation then. "
        "Recommended value is, e.g., --alpha 0.8")

    args = input_parser.parse_args()
    input_parser.print_arguments(args)

    if args.log_config:
        input_parser.log_config(os.path.abspath(__file__))

    filename_srr = "srr"
    dir_output_preprocessing = os.path.join(args.dir_output,
                                            "preprocessing_n4itk")
    dir_output_recon_subject_space = os.path.join(args.dir_output,
                                                  "recon_subject_space")
    dir_output_recon_template_space = os.path.join(args.dir_output,
                                                   "recon_template_space")
    dir_output_data_vs_simulatd_data = os.path.join(args.dir_output,
                                                    "data_vs_simulated_data")

    srr_subject = os.path.join(dir_output_recon_subject_space,
                               "%s_subject.nii.gz" % filename_srr)
    srr_subject_mask = ph.append_to_filename(srr_subject, "_mask")
    srr_template = os.path.join(dir_output_recon_template_space,
                                "%s_template.nii.gz" % filename_srr)
    srr_template_mask = ph.append_to_filename(srr_template, "_mask")
    trafo_template = os.path.join(dir_output_recon_template_space,
                                  "registration_transform_sitk.txt")

    if args.target_stack is None:
        target_stack = args.filenames[0]
    else:
        target_stack = args.target_stack

    if args.bias_field_correction and args.run_bias_field_correction:
        for i, f in enumerate(args.filenames):
            output = os.path.join(dir_output_preprocessing,
                                  os.path.basename(f))
            cmd_args = []
            cmd_args.append("--filename %s" % f)
            cmd_args.append("--filename-mask %s" % args.filenames_masks[i])
            cmd_args.append("--output %s" % output)
            # cmd_args.append("--verbose %d" % args.verbose)
            cmd = "niftymic_correct_bias_field %s" % (" ").join(cmd_args)
            time_start_bias = ph.start_timing()
            exit_code = ph.execute_command(cmd)
            if exit_code != 0:
                raise RuntimeError("Bias field correction failed")
        elapsed_time_bias = ph.stop_timing(time_start_bias)
        filenames = [
            os.path.join(dir_output_preprocessing, os.path.basename(f))
            for f in args.filenames
        ]
    elif args.bias_field_correction and not args.run_bias_field_correction:
        elapsed_time_bias = ph.get_zero_time()
        filenames = [
            os.path.join(dir_output_preprocessing, os.path.basename(f))
            for f in args.filenames
        ]
    else:
        elapsed_time_bias = ph.get_zero_time()
        filenames = args.filenames

    if args.run_recon_subject_space:
        target_stack_index = args.filenames.index(target_stack)

        cmd_args = []
        cmd_args.append("--filenames %s" % (" ").join(filenames))
        if args.filenames_masks is not None:
            cmd_args.append("--filenames-masks %s" %
                            (" ").join(args.filenames_masks))
        cmd_args.append("--multiresolution %d" % args.multiresolution)
        cmd_args.append("--target-stack-index %d" % target_stack_index)
        cmd_args.append("--output %s" % srr_subject)
        cmd_args.append("--suffix-mask '%s'" % args.suffix_mask)
        cmd_args.append("--intensity-correction %d" %
                        args.intensity_correction)
        cmd_args.append("--alpha %s" % args.alpha)
        cmd_args.append("--iter-max %d" % args.iter_max)
        cmd_args.append("--two-step-cycles %d" % args.two_step_cycles)
        cmd_args.append("--outlier-rejection %d" % args.outlier_rejection)
        cmd_args.append("--verbose %d" % args.verbose)
        if args.isotropic_resolution is not None:
            cmd_args.append("--isotropic-resolution %f" %
                            args.isotropic_resolution)
        if args.reference is not None:
            cmd_args.append("--reference %s" % args.reference)
        if args.reference_mask is not None:
            cmd_args.append("--reference-mask %s" % args.reference_mask)
        if args.sda:
            cmd_args.append("--sda")
        cmd = "niftymic_reconstruct_volume %s" % (" ").join(cmd_args)
        time_start_volrec = ph.start_timing()
        exit_code = ph.execute_command(cmd)
        if exit_code != 0:
            raise RuntimeError("Reconstruction in subject space failed")

        # Compute SRR mask in subject space
        # (Approximated using SDA within reconstruct_volume)
        if 0:
            dir_motion_correction = os.path.join(
                dir_output_recon_subject_space, "motion_correction")
            cmd_args = ["niftymic_reconstruct_volume_from_slices"]
            cmd_args.append("--filenames %s" % " ".join(args.filenames_masks))
            cmd_args.append("--dir-input-mc %s" % dir_motion_correction)
            cmd_args.append("--output %s" % srr_subject_mask)
            cmd_args.append("--reconstruction-space %s" % srr_subject)
            cmd_args.append("--suffix-mask '%s'" % args.suffix_mask)
            cmd_args.append("--mask")
            if args.sda:
                cmd_args.append("--sda")
                cmd_args.append("--alpha 1")
            else:
                cmd_args.append("--alpha 0.1")
                cmd_args.append("--iter-max 5")
            cmd = (" ").join(cmd_args)
            ph.execute_command(cmd)

        elapsed_time_volrec = ph.stop_timing(time_start_volrec)
    else:
        elapsed_time_volrec = ph.get_zero_time()

    if args.run_recon_template_space:

        if args.gestational_age is None:
            template_stack_estimator = \
                tse.TemplateStackEstimator.from_mask(srr_subject_mask)
            gestational_age = template_stack_estimator.get_estimated_gw()
            ph.print_info("Estimated gestational age: %d" % gestational_age)
        else:
            gestational_age = args.gestational_age

        template = os.path.join(DIR_TEMPLATES,
                                "STA%d.nii.gz" % gestational_age)
        template_mask = os.path.join(DIR_TEMPLATES,
                                     "STA%d_mask.nii.gz" % gestational_age)

        cmd_args = []
        cmd_args.append("--fixed %s" % template)
        cmd_args.append("--moving %s" % srr_subject)
        cmd_args.append("--fixed-mask %s" % template_mask)
        cmd_args.append("--moving-mask %s" % srr_subject_mask)
        cmd_args.append(
            "--dir-input-mc %s" %
            os.path.join(dir_output_recon_subject_space, "motion_correction"))
        cmd_args.append("--output %s" % trafo_template)
        cmd_args.append("--verbose %s" % args.verbose)
        if args.initial_transform is not None:
            cmd_args.append("--initial-transform %s" % args.initial_transform)
            cmd_args.append("--use-flirt 0")
            cmd_args.append("--test-ap-flip 0")
        cmd = "niftymic_register_image %s" % (" ").join(cmd_args)
        exit_code = ph.execute_command(cmd)
        if exit_code != 0:
            raise RuntimeError("Registration to template space failed")

        # reconstruct volume in template space
        # pattern = "[a-zA-Z0-9_.]+(ResamplingToTemplateSpace.nii.gz)"
        # p = re.compile(pattern)
        # reconstruction_space = [
        #     os.path.join(dir_output_recon_template_space, p.match(f).group(0))
        #     for f in os.listdir(dir_output_recon_template_space)
        #     if p.match(f)][0]

        dir_input_mc = os.path.join(dir_output_recon_template_space,
                                    "motion_correction")
        cmd_args = ["niftymic_reconstruct_volume_from_slices"]
        cmd_args.append("--filenames %s" % (" ").join(filenames))
        cmd_args.append("--dir-input-mc %s" % dir_input_mc)
        cmd_args.append("--output %s" % srr_template)
        cmd_args.append("--reconstruction-space %s" % template)
        cmd_args.append("--iter-max %d" % args.iter_max)
        cmd_args.append("--alpha %s" % args.alpha)
        cmd_args.append("--suffix-mask '%s'" % args.suffix_mask)
        cmd_args.append("--verbose %s" % args.verbose)
        if args.sda:
            cmd_args.append("--sda")

        cmd = (" ").join(cmd_args)
        exit_code = ph.execute_command(cmd)
        if exit_code != 0:
            raise RuntimeError("Reconstruction in template space failed")

        # Compute SRR mask in template space
        if 1:
            dir_motion_correction = os.path.join(
                dir_output_recon_template_space, "motion_correction")
            cmd_args = ["niftymic_reconstruct_volume_from_slices"]
            cmd_args.append("--filenames %s" % " ".join(args.filenames_masks))
            cmd_args.append("--dir-input-mc %s" % dir_motion_correction)
            cmd_args.append("--output %s" % srr_template_mask)
            cmd_args.append("--reconstruction-space %s" % srr_template)
            cmd_args.append("--suffix-mask '%s'" % args.suffix_mask)
            cmd_args.append("--mask")
            if args.sda:
                cmd_args.append("--sda")
                cmd_args.append("--alpha 1")
            else:
                cmd_args.append("--alpha 0.1")
                cmd_args.append("--iter-max 5")
            cmd = (" ").join(cmd_args)
            ph.execute_command(cmd)

        # Copy SRR to output directory
        output = "%sSRR_Stacks%d.nii.gz" % (args.prefix_output,
                                            len(args.filenames))
        path_to_output = os.path.join(args.dir_output, output)
        cmd = "cp -p %s %s" % (srr_template, path_to_output)
        exit_code = ph.execute_command(cmd)
        if exit_code != 0:
            raise RuntimeError("Copy of SRR to output directory failed")

        # Multiply template mask with reconstruction
        cmd_args = ["niftymic_multiply"]
        fnames = [
            srr_template,
            srr_template_mask,
        ]
        output_masked = "Masked_%s" % output
        path_to_output_masked = os.path.join(args.dir_output, output_masked)
        cmd_args.append("--filenames %s" % " ".join(fnames))
        cmd_args.append("--output %s" % path_to_output_masked)
        cmd = (" ").join(cmd_args)
        exit_code = ph.execute_command(cmd)
        if exit_code != 0:
            raise RuntimeError("SRR brain masking failed")

    else:
        elapsed_time_template = ph.get_zero_time()

    if args.run_data_vs_simulated_data:

        dir_input_mc = os.path.join(dir_output_recon_template_space,
                                    "motion_correction")

        # Get simulated/projected slices
        cmd_args = []
        cmd_args.append("--filenames %s" % (" ").join(filenames))
        if args.filenames_masks is not None:
            cmd_args.append("--filenames-masks %s" %
                            (" ").join(args.filenames_masks))
        cmd_args.append("--dir-input-mc %s" % dir_input_mc)
        cmd_args.append("--dir-output %s" % dir_output_data_vs_simulatd_data)
        cmd_args.append("--reconstruction %s" % srr_template)
        cmd_args.append("--copy-data 1")
        cmd_args.append("--suffix-mask '%s'" % args.suffix_mask)
        # cmd_args.append("--verbose %s" % args.verbose)
        exe = os.path.abspath(simulate_stacks_from_reconstruction.__file__)
        cmd = "python %s %s" % (exe, (" ").join(cmd_args))
        exit_code = ph.execute_command(cmd)
        if exit_code != 0:
            raise RuntimeError("SRR slice projections failed")

        filenames_simulated = [
            os.path.join(dir_output_data_vs_simulatd_data, os.path.basename(f))
            for f in filenames
        ]

        dir_output_evaluation = os.path.join(dir_output_data_vs_simulatd_data,
                                             "evaluation")
        dir_output_figures = os.path.join(dir_output_data_vs_simulatd_data,
                                          "figures")
        dir_output_side_by_side = os.path.join(dir_output_figures,
                                               "side-by-side")

        # Evaluate slice similarities to ground truth
        cmd_args = []
        cmd_args.append("--filenames %s" % (" ").join(filenames_simulated))
        if args.filenames_masks is not None:
            cmd_args.append("--filenames-masks %s" %
                            (" ").join(args.filenames_masks))
        cmd_args.append("--suffix-mask '%s'" % args.suffix_mask)
        cmd_args.append("--measures NCC SSIM")
        cmd_args.append("--dir-output %s" % dir_output_evaluation)
        exe = os.path.abspath(evaluate_simulated_stack_similarity.__file__)
        cmd = "python %s %s" % (exe, (" ").join(cmd_args))
        exit_code = ph.execute_command(cmd)
        if exit_code != 0:
            raise RuntimeError("Evaluation of slice similarities failed")

        # Generate figures showing the quantitative comparison
        cmd_args = []
        cmd_args.append("--dir-input %s" % dir_output_evaluation)
        cmd_args.append("--dir-output %s" % dir_output_figures)
        exe = os.path.abspath(
            show_evaluated_simulated_stack_similarity.__file__)
        cmd = "python %s %s" % (exe, (" ").join(cmd_args))
        exit_code = ph.execute_command(cmd)
        if exit_code != 0:
            ph.print_warning("Visualization of slice similarities failed")

        # Generate pdfs showing all the side-by-side comparisons
        cmd_args = []
        cmd_args.append("--filenames %s" % (" ").join(filenames_simulated))
        cmd_args.append("--dir-output %s" % dir_output_side_by_side)
        exe = os.path.abspath(
            export_side_by_side_simulated_vs_original_slice_comparison.__file__
        )
        cmd = "python %s %s" % (exe, (" ").join(cmd_args))
        exit_code = ph.execute_command(cmd)
        if exit_code != 0:
            raise RuntimeError("Generation of PDF overview failed")

    ph.print_title("Summary")
    print("Computational Time for Bias Field Correction: %s" %
          elapsed_time_bias)
    print("Computational Time for Volumetric Reconstruction: %s" %
          elapsed_time_volrec)
    print("Computational Time for Pipeline: %s" % ph.stop_timing(time_start))

    return 0
def main():

    time_start = ph.start_timing()

    np.set_printoptions(precision=3)

    input_parser = InputArgparser(
        description="Run reconstruction pipeline including "
        "(i) bias field correction, "
        "(ii) volumetric reconstruction in subject space, "
        "(iii) volumetric reconstruction in template space, "
        "and (iv) some diagnostics to assess the obtained reconstruction.", )
    input_parser.add_filenames(required=True)
    input_parser.add_filenames_masks(required=True)
    input_parser.add_target_stack(required=False)
    input_parser.add_suffix_mask(default="")
    input_parser.add_dir_output(required=True)
    input_parser.add_alpha(default=0.01)
    input_parser.add_verbose(default=0)
    input_parser.add_gestational_age(required=False)
    input_parser.add_prefix_output(default="")
    input_parser.add_search_angle(default=180)
    input_parser.add_multiresolution(default=0)
    input_parser.add_log_config(default=1)
    input_parser.add_isotropic_resolution()
    input_parser.add_reference()
    input_parser.add_reference_mask()
    input_parser.add_bias_field_correction(default=1)
    input_parser.add_intensity_correction(default=1)
    input_parser.add_iter_max(default=10)
    input_parser.add_two_step_cycles(default=3)
    input_parser.add_slice_thicknesses(default=None)
    input_parser.add_option(
        option_string="--run-bias-field-correction",
        type=int,
        help="Turn on/off bias field correction. "
        "If off, it is assumed that this step was already performed "
        "if --bias-field-correction is active.",
        default=1)
    input_parser.add_option(
        option_string="--run-recon-subject-space",
        type=int,
        help="Turn on/off reconstruction in subject space. "
        "If off, it is assumed that this step was already performed.",
        default=1)
    input_parser.add_option(
        option_string="--run-recon-template-space",
        type=int,
        help="Turn on/off reconstruction in template space. "
        "If off, it is assumed that this step was already performed.",
        default=1)
    input_parser.add_option(
        option_string="--run-diagnostics",
        type=int,
        help="Turn on/off diagnostics of the obtained volumetric "
        "reconstruction. ",
        default=0)
    input_parser.add_option(
        option_string="--initial-transform",
        type=str,
        help="Set initial transform to be used for register_image.",
        default=None)
    input_parser.add_outlier_rejection(default=1)
    input_parser.add_threshold_first(default=0.5)
    input_parser.add_threshold(default=0.8)
    input_parser.add_argument(
        "--sda",
        "-sda",
        action='store_true',
        help="If given, the volume is reconstructed using "
        "Scattered Data Approximation (Vercauteren et al., 2006). "
        "--alpha is considered the value for the standard deviation then. "
        "Recommended value is, e.g., --alpha 0.8")
    input_parser.add_argument(
        "--v2v-robust",
        "-v2v-robust",
        action='store_true',
        help="If given, a more robust volume-to-volume registration step is "
        "performed, i.e. four rigid registrations are performed using four "
        "rigid transform initializations based on "
        "principal component alignment of associated masks.")
    input_parser.add_interleave(default=3)
    input_parser.add_argument(
        "--s2v-hierarchical",
        "-s2v-hierarchical",
        action='store_true',
        help="If given, a hierarchical approach for the first slice-to-volume "
        "registration cycle is used, i.e. sub-packages defined by the "
        "specified interleave (--interleave) are registered until each "
        "slice is registered independently.")

    args = input_parser.parse_args()
    input_parser.print_arguments(args)

    if args.log_config:
        input_parser.log_config(os.path.abspath(__file__))

    filename_srr = "srr"
    dir_output_preprocessing = os.path.join(args.dir_output,
                                            "preprocessing_n4itk")
    dir_output_recon_subject_space = os.path.join(args.dir_output,
                                                  "recon_subject_space")
    dir_output_recon_template_space = os.path.join(args.dir_output,
                                                   "recon_template_space")
    dir_output_diagnostics = os.path.join(args.dir_output, "diagnostics")

    srr_subject = os.path.join(dir_output_recon_subject_space,
                               "%s_subject.nii.gz" % filename_srr)
    srr_subject_mask = ph.append_to_filename(srr_subject, "_mask")
    srr_template = os.path.join(dir_output_recon_template_space,
                                "%s_template.nii.gz" % filename_srr)
    srr_template_mask = ph.append_to_filename(srr_template, "_mask")
    trafo_template = os.path.join(dir_output_recon_template_space,
                                  "registration_transform_sitk.txt")
    srr_slice_coverage = os.path.join(
        dir_output_diagnostics,
        "%s_template_slicecoverage.nii.gz" % filename_srr)

    if args.bias_field_correction and args.run_bias_field_correction:
        for i, f in enumerate(args.filenames):
            output = os.path.join(dir_output_preprocessing,
                                  os.path.basename(f))
            cmd_args = []
            cmd_args.append("--filename '%s'" % f)
            cmd_args.append("--filename-mask '%s'" % args.filenames_masks[i])
            cmd_args.append("--output '%s'" % output)
            # cmd_args.append("--verbose %d" % args.verbose)
            cmd_args.append("--log-config %d" % args.log_config)
            cmd = "niftymic_correct_bias_field %s" % (" ").join(cmd_args)
            time_start_bias = ph.start_timing()
            exit_code = ph.execute_command(cmd)
            if exit_code != 0:
                raise RuntimeError("Bias field correction failed")
        elapsed_time_bias = ph.stop_timing(time_start_bias)
        filenames = [
            os.path.join(dir_output_preprocessing, os.path.basename(f))
            for f in args.filenames
        ]
    elif args.bias_field_correction and not args.run_bias_field_correction:
        elapsed_time_bias = ph.get_zero_time()
        filenames = [
            os.path.join(dir_output_preprocessing, os.path.basename(f))
            for f in args.filenames
        ]
    else:
        elapsed_time_bias = ph.get_zero_time()
        filenames = args.filenames

    # Specify target stack for intensity correction and reconstruction space
    if args.target_stack is None:
        target_stack = filenames[0]
    else:
        try:
            target_stack_index = args.filenames.index(args.target_stack)
        except ValueError as e:
            raise ValueError(
                "--target-stack must correspond to an image as provided by "
                "--filenames")
        target_stack = filenames[target_stack_index]

    # Add single quotes around individual filenames to account for whitespaces
    filenames = ["'" + f + "'" for f in filenames]
    filenames_masks = ["'" + f + "'" for f in args.filenames_masks]

    if args.run_recon_subject_space:

        cmd_args = ["niftymic_reconstruct_volume"]
        cmd_args.append("--filenames %s" % (" ").join(filenames))
        cmd_args.append("--filenames-masks %s" % (" ").join(filenames_masks))
        cmd_args.append("--multiresolution %d" % args.multiresolution)
        cmd_args.append("--target-stack '%s'" % target_stack)
        cmd_args.append("--output '%s'" % srr_subject)
        cmd_args.append("--suffix-mask '%s'" % args.suffix_mask)
        cmd_args.append("--intensity-correction %d" %
                        args.intensity_correction)
        cmd_args.append("--alpha %s" % args.alpha)
        cmd_args.append("--iter-max %d" % args.iter_max)
        cmd_args.append("--two-step-cycles %d" % args.two_step_cycles)
        cmd_args.append("--outlier-rejection %d" % args.outlier_rejection)
        cmd_args.append("--threshold-first %f" % args.threshold_first)
        cmd_args.append("--threshold %f" % args.threshold)
        if args.slice_thicknesses is not None:
            cmd_args.append("--slice-thicknesses %s" %
                            " ".join(map(str, args.slice_thicknesses)))
        cmd_args.append("--verbose %d" % args.verbose)
        cmd_args.append("--log-config %d" % args.log_config)
        if args.isotropic_resolution is not None:
            cmd_args.append("--isotropic-resolution %f" %
                            args.isotropic_resolution)
        if args.reference is not None:
            cmd_args.append("--reference %s" % args.reference)
        if args.reference_mask is not None:
            cmd_args.append("--reference-mask %s" % args.reference_mask)
        if args.sda:
            cmd_args.append("--sda")
        if args.v2v_robust:
            cmd_args.append("--v2v-robust")
        if args.s2v_hierarchical:
            cmd_args.append("--s2v-hierarchical")

        cmd = (" ").join(cmd_args)
        time_start_volrec = ph.start_timing()
        exit_code = ph.execute_command(cmd)
        if exit_code != 0:
            raise RuntimeError("Reconstruction in subject space failed")

        # Compute SRR mask in subject space
        # (Approximated using SDA within reconstruct_volume)
        if 0:
            dir_motion_correction = os.path.join(
                dir_output_recon_subject_space, "motion_correction")
            cmd_args = ["niftymic_reconstruct_volume_from_slices"]
            cmd_args.append("--filenames %s" % " ".join(filenames_masks))
            cmd_args.append("--dir-input-mc '%s'" % dir_motion_correction)
            cmd_args.append("--output '%s'" % srr_subject_mask)
            cmd_args.append("--reconstruction-space '%s'" % srr_subject)
            cmd_args.append("--suffix-mask '%s'" % args.suffix_mask)
            cmd_args.append("--mask")
            cmd_args.append("--log-config %d" % args.log_config)
            if args.slice_thicknesses is not None:
                cmd_args.append("--slice-thicknesses %s" %
                                " ".join(map(str, args.slice_thicknesses)))
            if args.sda:
                cmd_args.append("--sda")
                cmd_args.append("--alpha 1")
            else:
                cmd_args.append("--alpha 0.1")
                cmd_args.append("--iter-max 5")
            cmd = (" ").join(cmd_args)
            ph.execute_command(cmd)

        elapsed_time_volrec = ph.stop_timing(time_start_volrec)
    else:
        elapsed_time_volrec = ph.get_zero_time()

    if args.run_recon_template_space:

        if args.gestational_age is None:
            template_stack_estimator = \
                tse.TemplateStackEstimator.from_mask(srr_subject_mask)
            gestational_age = template_stack_estimator.get_estimated_gw()
            ph.print_info("Estimated gestational age: %d" % gestational_age)
        else:
            gestational_age = args.gestational_age

        template = os.path.join(DIR_TEMPLATES,
                                "STA%d.nii.gz" % gestational_age)
        template_mask = os.path.join(DIR_TEMPLATES,
                                     "STA%d_mask.nii.gz" % gestational_age)

        # Register SRR to template space
        cmd_args = ["niftymic_register_image"]
        cmd_args.append("--fixed '%s'" % template)
        cmd_args.append("--moving '%s'" % srr_subject)
        cmd_args.append("--fixed-mask '%s'" % template_mask)
        cmd_args.append("--moving-mask '%s'" % srr_subject_mask)
        cmd_args.append(
            "--dir-input-mc '%s'" %
            os.path.join(dir_output_recon_subject_space, "motion_correction"))
        cmd_args.append("--output '%s'" % trafo_template)
        cmd_args.append("--verbose %s" % args.verbose)
        cmd_args.append("--log-config %d" % args.log_config)
        cmd_args.append("--refine-pca")
        if args.initial_transform is not None:
            cmd_args.append("--initial-transform '%s'" %
                            args.initial_transform)
        cmd = (" ").join(cmd_args)
        exit_code = ph.execute_command(cmd)
        if exit_code != 0:
            raise RuntimeError("Registration to template space failed")

        # Compute SRR in template space
        dir_input_mc = os.path.join(dir_output_recon_template_space,
                                    "motion_correction")
        cmd_args = ["niftymic_reconstruct_volume_from_slices"]
        cmd_args.append("--filenames %s" % (" ").join(filenames))
        cmd_args.append("--filenames-masks %s" % (" ").join(filenames_masks))
        cmd_args.append("--dir-input-mc '%s'" % dir_input_mc)
        cmd_args.append("--output '%s'" % srr_template)
        cmd_args.append("--reconstruction-space '%s'" % template)
        cmd_args.append("--target-stack '%s'" % target_stack)
        cmd_args.append("--iter-max %d" % args.iter_max)
        cmd_args.append("--alpha %s" % args.alpha)
        cmd_args.append("--suffix-mask '%s'" % args.suffix_mask)
        cmd_args.append("--verbose %s" % args.verbose)
        cmd_args.append("--log-config %d" % args.log_config)
        if args.slice_thicknesses is not None:
            cmd_args.append("--slice-thicknesses %s" %
                            " ".join(map(str, args.slice_thicknesses)))
        if args.sda:
            cmd_args.append("--sda")

        cmd = (" ").join(cmd_args)
        exit_code = ph.execute_command(cmd)
        if exit_code != 0:
            raise RuntimeError("Reconstruction in template space failed")

        # Compute SRR mask in template space
        if 1:
            dir_motion_correction = os.path.join(
                dir_output_recon_template_space, "motion_correction")
            cmd_args = ["niftymic_reconstruct_volume_from_slices"]
            cmd_args.append("--filenames %s" % " ".join(filenames_masks))
            cmd_args.append("--dir-input-mc '%s'" % dir_motion_correction)
            cmd_args.append("--output '%s'" % srr_template_mask)
            cmd_args.append("--reconstruction-space '%s'" % srr_template)
            cmd_args.append("--suffix-mask '%s'" % args.suffix_mask)
            cmd_args.append("--log-config %d" % args.log_config)
            cmd_args.append("--mask")
            if args.slice_thicknesses is not None:
                cmd_args.append("--slice-thicknesses %s" %
                                " ".join(map(str, args.slice_thicknesses)))
            if args.sda:
                cmd_args.append("--sda")
                cmd_args.append("--alpha 1")
            else:
                cmd_args.append("--alpha 0.1")
                cmd_args.append("--iter-max 5")
            cmd = (" ").join(cmd_args)
            ph.execute_command(cmd)

        # Copy SRR to output directory
        if 0:
            output = "%sSRR_Stacks%d.nii.gz" % (args.prefix_output,
                                                len(args.filenames))
            path_to_output = os.path.join(args.dir_output, output)
            cmd = "cp -p '%s' '%s'" % (srr_template, path_to_output)
            exit_code = ph.execute_command(cmd)
            if exit_code != 0:
                raise RuntimeError("Copy of SRR to output directory failed")

        # Multiply template mask with reconstruction
        if 0:
            cmd_args = ["niftymic_multiply"]
            fnames = [
                srr_template,
                srr_template_mask,
            ]
            output_masked = "Masked_%s" % output
            path_to_output_masked = os.path.join(args.dir_output,
                                                 output_masked)
            cmd_args.append("--filenames %s" % " ".join(fnames))
            cmd_args.append("--output '%s'" % path_to_output_masked)
            cmd = (" ").join(cmd_args)
            exit_code = ph.execute_command(cmd)
            if exit_code != 0:
                raise RuntimeError("SRR brain masking failed")

    else:
        elapsed_time_template = ph.get_zero_time()

    if args.run_diagnostics:

        dir_input_mc = os.path.join(dir_output_recon_template_space,
                                    "motion_correction")
        dir_output_orig_vs_proj = os.path.join(dir_output_diagnostics,
                                               "original_vs_projected")
        dir_output_selfsimilarity = os.path.join(dir_output_diagnostics,
                                                 "selfsimilarity")
        dir_output_orig_vs_proj_pdf = os.path.join(dir_output_orig_vs_proj,
                                                   "pdf")

        # Show slice coverage over reconstruction space
        exe = os.path.abspath(show_slice_coverage.__file__)
        cmd_args = ["python %s" % exe]
        cmd_args.append("--filenames %s" % (" ").join(filenames))
        cmd_args.append("--dir-input-mc '%s'" % dir_input_mc)
        cmd_args.append("--reconstruction-space '%s'" % srr_template)
        cmd_args.append("--output '%s'" % srr_slice_coverage)
        cmd = (" ").join(cmd_args)
        exit_code = ph.execute_command(cmd)
        if exit_code != 0:
            raise RuntimeError("Slice coverage visualization failed")

        # Get simulated/projected slices
        exe = os.path.abspath(simulate_stacks_from_reconstruction.__file__)
        cmd_args = ["python %s" % exe]
        cmd_args.append("--filenames %s" % (" ").join(filenames))
        if args.filenames_masks is not None:
            cmd_args.append("--filenames-masks %s" %
                            (" ").join(filenames_masks))
        cmd_args.append("--dir-input-mc '%s'" % dir_input_mc)
        cmd_args.append("--dir-output '%s'" % dir_output_orig_vs_proj)
        cmd_args.append("--reconstruction '%s'" % srr_template)
        cmd_args.append("--copy-data 1")
        if args.slice_thicknesses is not None:
            cmd_args.append("--slice-thicknesses %s" %
                            " ".join(map(str, args.slice_thicknesses)))
        # cmd_args.append("--verbose %s" % args.verbose)
        cmd = (" ").join(cmd_args)
        exit_code = ph.execute_command(cmd)
        if exit_code != 0:
            raise RuntimeError("SRR slice projections failed")

        filenames_simulated = [
            "'%s" % os.path.join(dir_output_orig_vs_proj, os.path.basename(f))
            for f in filenames
        ]

        # Evaluate slice similarities to ground truth
        exe = os.path.abspath(evaluate_simulated_stack_similarity.__file__)
        cmd_args = ["python %s" % exe]
        cmd_args.append("--filenames %s" % (" ").join(filenames_simulated))
        if args.filenames_masks is not None:
            cmd_args.append("--filenames-masks %s" %
                            (" ").join(filenames_masks))
        cmd_args.append("--measures NCC SSIM")
        cmd_args.append("--dir-output '%s'" % dir_output_selfsimilarity)
        cmd = (" ").join(cmd_args)
        exit_code = ph.execute_command(cmd)
        if exit_code != 0:
            raise RuntimeError("Evaluation of stack similarities failed")

        # Generate figures showing the quantitative comparison
        exe = os.path.abspath(
            show_evaluated_simulated_stack_similarity.__file__)
        cmd_args = ["python %s" % exe]
        cmd_args.append("--dir-input '%s'" % dir_output_selfsimilarity)
        cmd_args.append("--dir-output '%s'" % dir_output_selfsimilarity)
        cmd = (" ").join(cmd_args)
        exit_code = ph.execute_command(cmd)
        if exit_code != 0:
            ph.print_warning("Visualization of stack similarities failed")

        # Generate pdfs showing all the side-by-side comparisons
        if 0:
            exe = os.path.abspath(
                export_side_by_side_simulated_vs_original_slice_comparison.
                __file__)
            cmd_args = ["python %s" % exe]
            cmd_args.append("--filenames %s" % (" ").join(filenames_simulated))
            cmd_args.append("--dir-output '%s'" % dir_output_orig_vs_proj_pdf)
            cmd = "python %s %s" % (exe, (" ").join(cmd_args))
            cmd = (" ").join(cmd_args)
            exit_code = ph.execute_command(cmd)
            if exit_code != 0:
                raise RuntimeError("Generation of PDF overview failed")

    ph.print_title("Summary")
    print("Computational Time for Bias Field Correction: %s" %
          elapsed_time_bias)
    print("Computational Time for Volumetric Reconstruction: %s" %
          elapsed_time_volrec)
    print("Computational Time for Pipeline: %s" % ph.stop_timing(time_start))

    return 0
def main():

    time_start = ph.start_timing()

    np.set_printoptions(precision=3)

    input_parser = InputArgparser(
        description="Run reconstruction pipeline including "
        "(i) preprocessing (bias field correction + intensity correction), "
        "(ii) volumetric reconstruction in subject space, "
        "and (iii) volumetric reconstruction in template space.",
    )
    input_parser.add_dir_input(required=True)
    input_parser.add_dir_mask(required=True)
    input_parser.add_dir_output(required=True)
    input_parser.add_suffix_mask(default="_mask")
    input_parser.add_target_stack(required=False)
    input_parser.add_alpha(default=0.01)
    input_parser.add_verbose(default=0)
    input_parser.add_gestational_age(required=False)
    input_parser.add_prefix_output(default="")
    input_parser.add_search_angle(default=180)
    input_parser.add_multiresolution(default=0)
    input_parser.add_log_script_execution(default=1)
    input_parser.add_dir_input_templates(default=DIR_TEMPLATES)
    input_parser.add_isotropic_resolution()
    input_parser.add_reference()
    input_parser.add_reference_mask()
    input_parser.add_bias_field_correction(default=1)
    input_parser.add_intensity_correction(default=1)
    input_parser.add_iter_max(default=10)
    input_parser.add_two_step_cycles(default=3)
    input_parser.add_option(
        option_string="--run-recon-subject-space",
        type=int,
        help="Turn on/off reconstruction in subject space",
        default=1)
    input_parser.add_option(
        option_string="--run-recon-template-space",
        type=int,
        help="Turn on/off reconstruction in template space",
        default=1)
    input_parser.add_option(
        option_string="--run-data-vs-simulated-data",
        type=int,
        help="Turn on/off comparison of data vs data simulated from the "
        "obtained volumetric reconstruction",
        default=1)
    input_parser.add_outlier_rejection(default=0)
    input_parser.add_use_robust_registration(default=0)

    args = input_parser.parse_args()
    input_parser.print_arguments(args)

    # Write script execution call
    if args.log_script_execution:
        input_parser.write_performed_script_execution(
            os.path.abspath(__file__))

    dir_output_recon_subject_space = os.path.join(
        args.dir_output, "recon_subject_space")
    dir_output_recon_template_space = os.path.join(
        args.dir_output, "recon_template_space")
    dir_output_data_vs_simulatd_data = os.path.join(
        args.dir_output, "data_vs_simulated_data")

#    if args.run_recon_template_space and args.gestational_age is None:
#        raise IOError("Gestational age must be set in order to pick the "
#                      "right template")

    # get input stack names
    files = os.listdir(args.dir_input)
    input_files = []
    mask_files  = []
    for file in files:
        if (".nii" in file):
            input_files.append("{0:}/{1:}".format(args.dir_input, file))
            file_prefix = file[:-7] if (".nii.gz" in file) else file[:-4]
            mask_name = "{0:}/{1:}.nii.gz".format(args.dir_mask, file_prefix)
            if(not os.path.isfile(mask_name)):
                mask_name = "{0:}/{1:}.nii".format(args.dir_mask, file_prefix)
            assert(os.path.isfile(mask_name))
            mask_files.append(mask_name)


    if args.target_stack is None:
        target_stack = input_files[0]
    else:
        target_stack = input_files

    if args.run_recon_subject_space:

        target_stack_index = input_files.index(target_stack)

        cmd_args = []
        cmd_args.append("--filenames %s" % (" ").join(input_files))
        cmd_args.append("--filenames-masks %s" % (" ").join(mask_files))
        cmd_args.append("--multiresolution %d" % args.multiresolution)
        cmd_args.append("--target-stack-index %d" % target_stack_index)
        cmd_args.append("--dir-output %s" % dir_output_recon_subject_space)
#        cmd_args.append("--suffix-mask %s" % args.suffix_mask)
        cmd_args.append("--intensity-correction %d" %
                        args.intensity_correction)
        cmd_args.append("--alpha %s" % args.alpha)
        cmd_args.append("--iter-max %d" % args.iter_max)
        cmd_args.append("--two-step-cycles %d" % args.two_step_cycles)
        cmd_args.append("--outlier-rejection %d" %
                        args.outlier_rejection)
        cmd_args.append("--use-robust-registration %d" %
                        args.use_robust_registration)
        cmd_args.append("--verbose %d" % args.verbose)
        if args.isotropic_resolution is not None:
            cmd_args.append("--isotropic-resolution %f" %
                            args.isotropic_resolution)
        if args.reference is not None:
            cmd_args.append("--reference %s" % args.reference)
        if args.reference_mask is not None:
            cmd_args.append("--reference-mask %s" % args.reference_mask)
        cmd = "niftymic_reconstruct_volume %s" % (" ").join(cmd_args)
        time_start_volrec = ph.start_timing()
        exit_code = ph.execute_command(cmd)
        if exit_code != 0:
            raise RuntimeError("Reconstruction in subject space failed")
        elapsed_time_volrec = ph.stop_timing(time_start_volrec)
    else:
        elapsed_time_volrec = ph.get_zero_time()

    if args.run_recon_template_space:
        # register recon to template space
        pattern = "[a-zA-Z0-9_]+(stacks)[a-zA-Z0-9_]+(.nii.gz)"
        p = re.compile(pattern)
        reconstruction = [
            os.path.join(
                dir_output_recon_subject_space, p.match(f).group(0))
            for f in os.listdir(dir_output_recon_subject_space)
            if p.match(f)][0]
            
        if('mask_manual' in args.dir_output):
            # find the corresponding template by volume matching
            reconstruction_mask = reconstruction
            if(not ("_mask" in reconstruction)):
                reconstruction_mask = ph.append_to_filename(reconstruction, "_mask")
            template_stack_estimator = \
                        tse.TemplateStackEstimator.from_mask(
                            reconstruction_mask,
                            args.dir_input_templates)
            template_mask = template_stack_estimator.get_path_to_template()
            template = template_mask.replace('_mask_dil.nii.gz', '.nii.gz')
            print('template name', template)
#            template = os.path.join(
#                        args.dir_input_templates,
#                        "STA%d.nii.gz" % args.gestational_age)
#            template_mask = os.path.join(
#                        args.dir_input_templates,
#                        "STA%d_mask.nii.gz" % args.gestational_age)
        else:
            template_folder = args.dir_output + "/../../mask_manual/reconstruct_outlier_gpr/"
            file_names = os.listdir(template_folder)
            template_names = [item for item in file_names if ("nii.gz" in item) and ("Masked" not in item)]
            mask_names = [item for item in file_names if ("nii.gz" in item) and ("Masked" in item)]
            template = os.path.join(template_folder, template_names[0])
            template_mask = os.path.join(template_folder, mask_names[0])

        cmd_args = []
        cmd_args.append("--moving %s" % reconstruction)
        cmd_args.append("--fixed %s" % template)
#        if(use_spatiotemporal_template is False):
#        cmd_args.append("--use-fixed-mask 1")  # added by Guotai
#        cmd_args.append("--template-mask %s" % template_mask) # micheal's code
        cmd_args.append("--dir-input %s" % os.path.join(
            dir_output_recon_subject_space,
            "motion_correction"))
        cmd_args.append("--dir-output %s" % dir_output_recon_template_space)
        cmd_args.append("--suffix-mask %s" % args.suffix_mask)
        cmd_args.append("--verbose %s" % args.verbose)
        cmd = "niftymic_register_image %s" % (" ").join(cmd_args)
        exit_code = ph.execute_command(cmd)
        if exit_code != 0:
            raise RuntimeError("Registration to template space failed")

        # reconstruct volume in template space
        # pattern = "[a-zA-Z0-9_.]+(ResamplingToTemplateSpace.nii.gz)"
        # p = re.compile(pattern)
        # reconstruction_space = [
        #     os.path.join(dir_output_recon_template_space, p.match(f).group(0))
        #     for f in os.listdir(dir_output_recon_template_space)
        #     if p.match(f)][0]

        dir_input = os.path.join(
            dir_output_recon_template_space, "motion_correction")
        cmd_args = []
        cmd_args.append("--dir-input %s" % dir_input)
        cmd_args.append("--dir-output %s" % dir_output_recon_template_space)
        cmd_args.append("--reconstruction-space %s" % template)
        cmd_args.append("--iter-max %d" % args.iter_max)
        cmd_args.append("--alpha %s" % args.alpha)
        cmd_args.append("--suffix-mask %s" % args.suffix_mask)

        cmd = "niftymic_reconstruct_volume_from_slices %s" % \
            (" ").join(cmd_args)
        exit_code = ph.execute_command(cmd)
        if exit_code != 0:
            raise RuntimeError("Reconstruction in template space failed")

        pattern = "[a-zA-Z0-9_.]+(stacks[0-9]+).*(.nii.gz)"
        p = re.compile(pattern)
        reconstruction = {
            p.match(f).group(1):
            os.path.join(
                dir_output_recon_template_space, p.match(f).group(0))
            for f in os.listdir(dir_output_recon_template_space)
            if p.match(f) and not p.match(f).group(0).endswith(
                "ResamplingToTemplateSpace.nii.gz")}
        key = reconstruction.keys()[0]
        path_to_recon = reconstruction[key]

        # Copy SRR to output directory
        output = "%sSRR_%s_GW%d.nii.gz" % (
            args.prefix_output, key, args.gestational_age)
        path_to_output = os.path.join(args.dir_output, output)
        cmd = "cp -p %s %s" % (path_to_recon, path_to_output)
        exit_code = ph.execute_command(cmd)
        if exit_code != 0:
            raise RuntimeError("Copy of SRR to output directory failed")

        # Multiply template mask with reconstruction
        cmd_args = []
        cmd_args.append("--filename %s" % path_to_output)
        cmd_args.append("--gestational-age %s" % args.gestational_age)
        cmd_args.append("--verbose %s" % args.verbose)
        cmd_args.append("--dir-input-templates %s " % args.dir_input_templates)
        cmd = "niftymic_multiply_stack_with_mask %s" % (
            " ").join(cmd_args)
        exit_code = ph.execute_command(cmd)
        if exit_code != 0:
            raise RuntimeError("SRR brain masking failed")

    else:
        elapsed_time_template = ph.get_zero_time()

    if args.run_data_vs_simulated_data:

        dir_input = os.path.join(
            dir_output_recon_template_space, "motion_correction")

        pattern = "[a-zA-Z0-9_.]+(stacks[0-9]+).*(.nii.gz)"
        # pattern = "Masked_[a-zA-Z0-9_.]+(stacks[0-9]+).*(.nii.gz)"
        p = re.compile(pattern)
        reconstruction = {
            p.match(f).group(1):
            os.path.join(
                dir_output_recon_template_space, p.match(f).group(0))
            for f in os.listdir(dir_output_recon_template_space)
            if p.match(f) and not p.match(f).group(0).endswith(
                "ResamplingToTemplateSpace.nii.gz")}
        key = reconstruction.keys()[0]
        path_to_recon = reconstruction[key]

        # Get simulated/projected slices
        cmd_args = []
        cmd_args.append("--dir-input %s" % dir_input)
        cmd_args.append("--dir-output %s" % dir_output_data_vs_simulatd_data)
        cmd_args.append("--reconstruction %s" % path_to_recon)
        cmd_args.append("--copy-data 1")
        cmd_args.append("--suffix-mask %s" % args.suffix_mask)
        # cmd_args.append("--verbose %s" % args.verbose)
        exe = os.path.abspath(simulate_stacks_from_reconstruction.__file__)
        cmd = "python %s %s" % (exe, (" ").join(cmd_args))
        exit_code = ph.execute_command(cmd)
        if exit_code != 0:
            raise RuntimeError("SRR slice projections failed")

        filenames_simulated = [
            os.path.join(dir_output_data_vs_simulatd_data, os.path.basename(f))
            for f in input_files]

        dir_output_evaluation = os.path.join(
            dir_output_data_vs_simulatd_data, "evaluation")
        dir_output_figures = os.path.join(
            dir_output_data_vs_simulatd_data, "figures")
        dir_output_side_by_side = os.path.join(
            dir_output_figures, "side-by-side")

        # Evaluate slice similarities to ground truth
        cmd_args = []
        cmd_args.append("--filenames %s" % (" ").join(filenames_simulated))
        cmd_args.append("--suffix-mask %s" % args.suffix_mask)
        cmd_args.append("--measures NCC SSIM")
        cmd_args.append("--dir-output %s" % dir_output_evaluation)
        exe = os.path.abspath(evaluate_simulated_stack_similarity.__file__)
        cmd = "python %s %s" % (exe, (" ").join(cmd_args))
        exit_code = ph.execute_command(cmd)
        if exit_code != 0:
            raise RuntimeError("Evaluation of slice similarities failed")

        # Generate figures showing the quantitative comparison
        cmd_args = []
        cmd_args.append("--dir-input %s" % dir_output_evaluation)
        cmd_args.append("--dir-output %s" % dir_output_figures)
        exe = os.path.abspath(
            show_evaluated_simulated_stack_similarity.__file__)
        cmd = "python %s %s" % (exe, (" ").join(cmd_args))
        exit_code = ph.execute_command(cmd)
        if exit_code != 0:
            ph.print_warning("Visualization of slice similarities failed")

        # Generate pdfs showing all the side-by-side comparisons
        cmd_args = []
        cmd_args.append("--filenames %s" % (" ").join(filenames_simulated))
        cmd_args.append("--dir-output %s" % dir_output_side_by_side)
        exe = os.path.abspath(
            export_side_by_side_simulated_vs_original_slice_comparison.__file__)
        cmd = "python %s %s" % (exe, (" ").join(cmd_args))
        exit_code = ph.execute_command(cmd)
        if exit_code != 0:
            raise RuntimeError("Generation of PDF overview failed")

    ph.print_title("Summary")
    print("Computational Time for Volumetric Reconstruction: %s" %
          elapsed_time_volrec)
    print("Computational Time for Pipeline: %s" %
          ph.stop_timing(time_start))

    return 0