Exemplo n.º 1
0
    def test_get_displacement_norm_between_images(self):

        shapes = {
            2: (100, 200),
            3: (100, 200, 50),
        }
        origin = {
            2: (-100, 10),
            3: (-100, 10, 33.3),
        }
        direction = {
            2: (0, -1, 1, 0),
            3: (0, 1, 0, 1, 0, 0, 0, 0, -1),
        }
        spacing = {
            2: (1.1, 2.5),
            3: (1.1, 2.5, 5),
        }

        parameters = {
            2: (-1.7, -10.23, 12),
            3: (0.3, -1.3, 2.1, -10.23, 12, 4),
        }
        center = {
            2: (-10, 15),
            3: (-10, 15, 17.3),
        }

        for dim in [2, 3]:
            print("Dimension: %d" % dim)
            transform_sitk = getattr(sitk, "Euler%dDTransform" % dim)()
            transform_sitk.SetParameters(parameters[dim])
            transform_sitk.SetCenter(center[dim])

            image_sitk = sitk.Image(shapes[dim], sitk.sitkFloat32)
            image_sitk.SetOrigin(origin[dim])
            image_sitk.SetDirection(direction[dim])
            image_sitk.SetSpacing(spacing[dim])

            # -------------------Compute mean displacements-------------------
            t0 = ph.start_timing()
            norm_disp = utils.get_voxel_displacements(image_sitk,
                                                      transform_sitk)
            print("Time method: %s" % ph.stop_timing(t0))

            # -----------------------Compute ref result-----------------------
            disp_shape = sitk.GetArrayFromImage(image_sitk).shape
            t0 = ph.start_timing()
            disp = np.zeros(disp_shape + (dim, ))
            for index in np.ndindex(shapes[dim]):
                point = image_sitk.TransformIndexToPhysicalPoint(index)
                point_ref = transform_sitk.TransformPoint(point)
                disp[index[::-1]] = point - np.array(point_ref)
            norm_disp_ref = np.sqrt(np.sum(np.square(disp), axis=-1))
            print("Time reference: %s" % ph.stop_timing(t0))

            self.assertAlmostEqual(np.linalg.norm(norm_disp - norm_disp_ref),
                                   0,
                                   places=self.precision)
Exemplo n.º 2
0
def main():
    pid = "49"
    method     = "manual" #auto, manual
    input_dir  = "{0:}/input".format(pid)
    mask_dir   = "{0:}/mask_{1:}/mask".format(pid, method)
    output_dir = "{0:}/input_preprocess".format(pid)

    # get input stack names
    files = os.listdir(input_dir)
    input_files = []
    mask_files  = []
    for file in files:
        if (("nii.gz" in file)):
            input_files.append("{0:}/{1:}".format(input_dir, file))
            mask_name = "{0:}/{1:}".format(mask_dir, file)
            assert(os.path.isfile(mask_name))
            mask_files.append(mask_name)

    cmd_args = []
    cmd_args.append("--filenames %s" % (" ").join(input_files))
    cmd_args.append("--filenames-masks %s" % (" ").join(mask_files))
    cmd_args.append("--dir-output %s" % output_dir)
    cmd_args.append("--prefix-output ''")
    cmd = "niftymic_correct_bias_field %s" % (" ").join(cmd_args)
    time_start_bias = ph.start_timing()
    exit_code = ph.execute_command(cmd)
    elapsed_time_bias = ph.stop_timing(time_start_bias)
    print("Computational Time for Bias Field Correction: %s" %
          elapsed_time_bias)
    if exit_code != 0:
        raise RuntimeError("Bias field correction failed")
    return 0
    def run_dilation(self):

        time_start = ph.start_timing()

        dilater = sitk.BinaryDilateImageFilter()
        dilater.SetKernelType(eval("sitk.sitk" + self._dilation_kernel))
        dilater.SetKernelRadius(self._dilation_radius)

        if self._use_dilation_in_plane_only:

            shape = self._mask_sitk.GetSize()
            N_slices = shape[2]
            nda_mask = np.zeros(shape[::-1], dtype=np.uint8)

            for i in range(0, N_slices):
                slice_mask_sitk = self._mask_sitk[:, :, i:i + 1]
                mask_sitk = dilater.Execute(slice_mask_sitk)
                nda_mask[i, :, :] = sitk.GetArrayFromImage(mask_sitk)

            mask_sitk = sitk.GetImageFromArray(nda_mask)
            mask_sitk.CopyInformation(self._mask_sitk)
            self._mask_sitk = mask_sitk

        else:
            self._mask_sitk = dilater.Execute(self._mask_sitk)

        if self._stack is not None:
            self._stack = st.Stack.from_sitk_image(
                self._stack.sitk,
                image_sitk_mask=self._mask_sitk,
                filename=self._stack.get_filename())

        self._computational_time = ph.stop_timing(time_start)
Exemplo n.º 4
0
    def run_bias_field_correction(self):

        time_start = ph.start_timing()

        bias_field_corrector = sitk.N4BiasFieldCorrectionImageFilter()

        bias_field_corrector.SetBiasFieldFullWidthAtHalfMaximum(
            self._bias_field_fwhm)
        bias_field_corrector.SetConvergenceThreshold(
            self._convergence_threshold)
        bias_field_corrector.SetSplineOrder(self._spline_order)
        bias_field_corrector.SetWienerFilterNoise(self._wiener_filter_noise)

        if self._use_mask:
            image_sitk = bias_field_corrector.Execute(self._stack.sitk,
                                                      self._stack.sitk_mask)
        else:
            image_sitk = bias_field_corrector.Execute(self._stack.sitk)

        # Reading of image might lead to slight differences
        stack_corrected_sitk_mask = sitk.Resample(
            self._stack.sitk_mask, image_sitk,
            sitk.Euler3DTransform(), sitk.sitkNearestNeighbor, 0,
            self._stack.sitk_mask.GetPixelIDValue())

        self._stack_corrected = st.Stack.from_sitk_image(
            image_sitk=image_sitk,
            image_sitk_mask=stack_corrected_sitk_mask,
            filename=self._prefix_corrected + self._stack.get_filename(),
        )

        # Get computational time
        self._computational_time = ph.stop_timing(time_start)
Exemplo n.º 5
0
    def run(self):

        if not isinstance(self._fixed_itk, self._image_type):
            raise ValueError("Fixed image must be of type itk.Image")

        if not isinstance(self._moving_itk, self._image_type):
            raise ValueError("Moving image must be of type itk.Image")

        if self._fixed_itk_mask is not None and \
                not isinstance(self._fixed_itk_mask, self._image_type):
            raise ValueError(
                "Fixed image mask must be of type itk.Image")

        if self._moving_itk_mask is not None and \
                not isinstance(self._moving_itk_mask, self._image_type):
            raise ValueError(
                "Moving image mask must be of type itk.Image")

        time_start = ph.start_timing()

        # Execute registration method
        self._run_v3()
        # self._run_v4()

        # Get computational time
        self._computational_time = ph.stop_timing(time_start)
    def from_volume(cls, file_paths_masks):
        t0 = ph.start_timing()
        target_stack_estimator = cls()

        volumes = np.array([
            TargetStackEstimator._compute_volume(f) for f in file_paths_masks
        ])

        # find index to smallest "valid" volume, i.e. volume > q * median
        index = np.argmax(
            volumes[np.argsort(volumes)] > 0.7 * np.median(volumes))
        index = np.argsort(volumes)[index]

        # Get index corresponding to maximum volume stack mask
        # index = np.argmax(volumes)
        # index = np.argmin(volumes)

        # Get index corresponding to median volume stack mask
        # index = np.argsort(volumes)[len(volumes)//2]

        target_stack_estimator._target_stack_index = index

        # computational time
        target_stack_estimator._computational_time = ph.stop_timing(t0)

        return target_stack_estimator
Exemplo n.º 7
0
    def test_translation_registration_of_slices(self):

        filename_prefix = "TranslationOnly_"
        # filename_prefix = "RigidTransform_"

        filename_HRVolume = "HRVolume"
        filename_StackSim = filename_prefix + "StackSimulated"
        filename_transforms_prefix = filename_prefix + "TransformGroundTruth_slice"
        stack_sim = st.Stack.from_filename(
            os.path.join(self.dir_test_data, filename_StackSim + ".nii.gz"))
        HR_volume = st.Stack.from_filename(
            os.path.join(self.dir_test_data, filename_HRVolume + ".nii.gz"))

        slices_sim = stack_sim.get_slices()
        N_slices = len(slices_sim)

        scale = np.array(
            [180. / np.pi, 180. / np.pi, 180. / np.pi, 1., 1., 1.])
        time_start = ph.start_timing()

        for j in range(0, N_slices):
            # for j in range(20, N_slices):
            rigid_transform_groundtruth_sitk = sitk.ReadTransform(
                self.dir_test_data + filename_transforms_prefix + str(j) +
                ".tfm")
            parameters_gd = np.array(
                rigid_transform_groundtruth_sitk.GetParameters())

            angle_max = 5. * np.pi / 180.
            t_max = 5.
            registration = myreg.Registration(
                fixed=slices_sim[j],
                moving=HR_volume,
                # initializer_type="SelfGEOMETRY",
                use_verbose=0,
                # data_loss="soft_l1",
                # x_scale=[angle_max, angle_max, angle_max, t_max, t_max, t_max],
            )
            registration.run_registration()
            # registration.print_statistics()

            # Check parameters
            transform_sitk = registration.get_registration_transform_sitk()
            parameters = np.array(transform_sitk.GetParameters())
            norm_diff = np.linalg.norm(parameters - parameters_gd)

            params = parameters * scale
            params_gt = parameters_gd * scale
            print("Slice %s/%s: |parameters-parameters_gd| = %s" %
                  (j, N_slices - 1, str(norm_diff)))
            print("\tEst:  " + str(params) + " (deg/mmm)")
            print("\tGT:   " + str(params_gt) + " (deg/mmm)")
            print("\tDiff: " + str(params - params_gt) + " (deg/mmm)")

            self.assertEqual(np.round(norm_diff, decimals=self.accuracy), 0)

        # Set elapsed time
        print("Translation: " + str(ph.stop_timing(time_start)))
    def run(self):

        time_start = ph.start_timing()

        self._run()

        self._computational_time = ph.stop_timing(time_start)

        if self._verbose:
            ph.print_info("Required computational time: %s" %
                          (self.get_computational_time()))
Exemplo n.º 9
0
    def run(self):
        ph.print_info("Chosen SDA approach: " + self._sda_approach)
        ph.print_info("Smoothing parameter sigma = " + str(self._sigma_array))

        time_start = ph.start_timing()

        self._run[self._sda_approach]()

        # Get computational time
        self._computational_time = ph.stop_timing(time_start)

        if self._verbose:
            ph.print_info("Required computational time: %s" %
                          (self.get_computational_time()))
    def run(self):
        if not isinstance(self._fixed_points_nda, np.ndarray):
            raise IOError("Fixed points must be of type np.array")

        if not isinstance(self._moving_points_nda, np.ndarray):
            raise IOError("Moving points must be of type np.array")

        if self._fixed_points_nda.shape[1] != self._moving_points_nda.shape[1]:
            raise IOError(
                "Spatial dimensions of fixed and moving points must be equal")

        # Execute registration method
        time_start = ph.start_timing()
        self._run()

        # Get computational time
        self._computational_time = ph.stop_timing(time_start)
Exemplo n.º 11
0
    def run(self):

        if not isinstance(self._fixed, st.Stack) and \
                not isinstance(self._fixed, sl.Slice):
            raise TypeError("Fixed image must be of type 'Stack' or 'Slice'")

        if not isinstance(self._moving, st.Stack) and \
                not isinstance(self._moving, sl.Slice):
            raise TypeError("Moving image must be of type 'Stack' or 'Slice'")

        time_start = ph.start_timing()

        # Execute registration method
        self._run()

        # Get computational time
        self._computational_time = ph.stop_timing(time_start)

        if self._use_verbose:
            ph.print_info("Required computational time: %s" %
                          (self.get_computational_time()))
Exemplo n.º 12
0
    def run(self):
        ph.create_directory(dir_tmp, delete_files=True)

        # Write images
        sitkh.write_nifti_image_sitk(
            self._stack1.sitk,
            self._dir_tmp + self._stack1.get_filename() + ".nii.gz")
        sitkh.write_nifti_image_sitk(
            self._stack2.sitk,
            self._dir_tmp + self._stack2.get_filename() + ".nii.gz")

        cmd = "siena "
        cmd += self._dir_tmp + self._stack1.get_filename() + ".nii.gz "
        cmd += self._dir_tmp + self._stack2.get_filename() + ".nii.gz "
        cmd += "-o " + self._dir_output + " "
        cmd += self._options

        time_start = ph.start_timing()
        ph.execute_command(cmd)
        self._elapsed_time = ph.stop_timing(time_start)

        # Extract measures from report
        self._extract_percentage_brain_volume_change()
Exemplo n.º 13
0
def main():

    time_start = ph.start_timing()

    np.set_printoptions(precision=3)

    input_parser = InputArgparser(
        description="Register an obtained reconstruction (moving) "
        "to a template image/space (fixed) using rigid registration. "
        "The resulting registration can optionally be applied to previously "
        "obtained motion correction slice transforms so that a volumetric "
        "reconstruction is possible in the (standard anatomical) space "
        "defined by the fixed.", )
    input_parser.add_fixed(required=True)
    input_parser.add_moving(required=True)
    input_parser.add_output(help="Path to registration transform (.txt)",
                            required=True)
    input_parser.add_fixed_mask(required=False)
    input_parser.add_moving_mask(required=False)
    input_parser.add_option(
        option_string="--initial-transform",
        type=str,
        help="Path to initial transform. "
        "If not provided, registration will be initialized based on "
        "rigid alignment of eigenbasis of the fixed/moving image masks "
        "using principal component analysis",
        default=None)
    input_parser.add_v2v_method(
        option_string="--method",
        help="Registration method used for the registration.",
        default="RegAladin",
    )
    input_parser.add_argument(
        "--refine-pca",
        "-refine-pca",
        action='store_true',
        help="If given, PCA-based initializations will be refined using "
        "RegAladin registrations.")
    input_parser.add_dir_input_mc()
    input_parser.add_verbose(default=0)
    input_parser.add_log_config(default=1)

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

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

    if not args.output.endswith(".txt"):
        raise IOError("output transformation path must end in '.txt'")

    dir_output = os.path.dirname(args.output)
    ph.create_directory(dir_output)

    # --------------------------------Read Data--------------------------------
    ph.print_title("Read Data")
    fixed = st.Stack.from_filename(file_path=args.fixed,
                                   file_path_mask=args.fixed_mask,
                                   extract_slices=False)
    moving = st.Stack.from_filename(file_path=args.moving,
                                    file_path_mask=args.moving_mask,
                                    extract_slices=False)

    path_to_tmp_output = os.path.join(
        DIR_TMP, ph.append_to_filename(os.path.basename(args.moving),
                                       "_warped"))

    # ---------------------------- Initialization ----------------------------
    if args.initial_transform is None:
        ph.print_title("Estimate initial transform using PCA")

        if args.moving_mask is None or args.fixed_mask is None:
            ph.print_warning("Fixed and moving masks are strongly recommended")
        transform_initializer = tinit.TransformInitializer(
            fixed=fixed,
            moving=moving,
            similarity_measure="NMI",
            refine_pca_initializations=args.refine_pca,
        )
        transform_initializer.run()
        transform_init_sitk = transform_initializer.get_transform_sitk()
    else:
        transform_init_sitk = sitkh.read_transform_sitk(args.initial_transform)
    sitk.WriteTransform(transform_init_sitk, args.output)

    # -------------------Register Reconstruction to Template-------------------
    ph.print_title("Registration")

    if args.method == "RegAladin":

        path_to_transform_regaladin = os.path.join(DIR_TMP,
                                                   "transform_regaladin.txt")

        # Convert SimpleITK to RegAladin transform
        cmd = "simplereg_transform -sitk2nreg %s %s" % (
            args.output, path_to_transform_regaladin)
        ph.execute_command(cmd, verbose=False)

        # Run NiftyReg
        cmd_args = ["reg_aladin"]
        cmd_args.append("-ref '%s'" % args.fixed)
        cmd_args.append("-flo '%s'" % args.moving)
        cmd_args.append("-res '%s'" % path_to_tmp_output)
        cmd_args.append("-inaff '%s'" % path_to_transform_regaladin)
        cmd_args.append("-aff '%s'" % path_to_transform_regaladin)
        cmd_args.append("-rigOnly")
        cmd_args.append("-ln 2")  # seems to perform better for spina bifida
        cmd_args.append("-voff")
        if args.fixed_mask is not None:
            cmd_args.append("-rmask '%s'" % args.fixed_mask)

        # To avoid error "0 correspondences between blocks were found" that can
        # occur for some cases. Also, disable moving mask, as this would be ignored
        # anyway
        cmd_args.append("-noSym")
        # if args.moving_mask is not None:
        #     cmd_args.append("-fmask '%s'" % args.moving_mask)

        ph.print_info("Run Registration (RegAladin) ... ", newline=False)
        ph.execute_command(" ".join(cmd_args), verbose=False)
        print("done")

        # Convert RegAladin to SimpleITK transform
        cmd = "simplereg_transform -nreg2sitk '%s' '%s'" % (
            path_to_transform_regaladin, args.output)
        ph.execute_command(cmd, verbose=False)

    else:
        path_to_transform_flirt = os.path.join(DIR_TMP, "transform_flirt.txt")

        # Convert SimpleITK into FLIRT transform
        cmd = "simplereg_transform -sitk2flirt '%s' '%s' '%s' '%s'" % (
            args.output, args.fixed, args.moving, path_to_transform_flirt)
        ph.execute_command(cmd, verbose=False)

        # Define search angle ranges for FLIRT in all three dimensions
        search_angles = [
            "-searchr%s -%d %d" % (x, 180, 180) for x in ["x", "y", "z"]
        ]

        cmd_args = ["flirt"]
        cmd_args.append("-in '%s'" % args.moving)
        cmd_args.append("-ref '%s'" % args.fixed)
        if args.initial_transform is not None:
            cmd_args.append("-init '%s'" % path_to_transform_flirt)
        cmd_args.append("-omat '%s'" % path_to_transform_flirt)
        cmd_args.append("-out '%s'" % path_to_tmp_output)
        cmd_args.append("-dof 6")
        cmd_args.append((" ").join(search_angles))
        if args.moving_mask is not None:
            cmd_args.append("-inweight '%s'" % args.moving_mask)
        if args.fixed_mask is not None:
            cmd_args.append("-refweight '%s'" % args.fixed_mask)
        ph.print_info("Run Registration (FLIRT) ... ", newline=False)
        ph.execute_command(" ".join(cmd_args), verbose=False)
        print("done")

        # Convert FLIRT to SimpleITK transform
        cmd = "simplereg_transform -flirt2sitk '%s' '%s' '%s' '%s'" % (
            path_to_transform_flirt, args.fixed, args.moving, args.output)
        ph.execute_command(cmd, verbose=False)

    if args.dir_input_mc is not None:
        ph.print_title("Update Motion-Correction Transformations")
        transform_sitk = sitkh.read_transform_sitk(args.output, inverse=1)

        if args.dir_input_mc.endswith("/"):
            subdir_mc = args.dir_input_mc.split("/")[-2]
        else:
            subdir_mc = args.dir_input_mc.split("/")[-1]
        dir_output_mc = os.path.join(dir_output, subdir_mc)

        ph.create_directory(dir_output_mc, delete_files=True)
        pattern = REGEX_FILENAMES + "[.]tfm"
        p = re.compile(pattern)
        trafos = [t for t in os.listdir(args.dir_input_mc) if p.match(t)]
        for t in trafos:
            path_to_input_transform = os.path.join(args.dir_input_mc, t)
            path_to_output_transform = os.path.join(dir_output_mc, t)
            t_sitk = sitkh.read_transform_sitk(path_to_input_transform)
            t_sitk = sitkh.get_composite_sitk_affine_transform(
                transform_sitk, t_sitk)
            sitk.WriteTransform(t_sitk, path_to_output_transform)
        ph.print_info("%d transformations written to '%s'" %
                      (len(trafos), dir_output_mc))

    if args.verbose:
        ph.show_niftis([args.fixed, path_to_tmp_output])

    elapsed_time_total = ph.stop_timing(time_start)

    # Summary
    ph.print_title("Summary")
    print("Computational Time: %s" % (elapsed_time_total))

    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, "
        "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
Exemplo n.º 15
0
def main():

    time_start = ph.start_timing()

    # Read input
    parser = argparse.ArgumentParser(
        description="Perform rigid registration using landmarks",
        prog=None,
        epilog="Author: Michael Ebner ([email protected])",
    )
    parser.add_argument(
        "-f",
        "--fixed",
        help="Path to fixed image landmarks.",
        type=str,
        required=1,
    )
    parser.add_argument(
        "-m",
        "--moving",
        help="Path to moving image landmarks.",
        type=str,
        required=1,
    )
    parser.add_argument(
        "-o",
        "--output",
        help="Path for obtained SimpleITK registration transform (.txt)",
        type=str,
        required=1,
    )
    parser.add_argument(
        "-v",
        "--verbose",
        help="Turn on/off verbose output",
        type=int,
        required=0,
        default=0,
    )
    parser.add_argument(
        "--pca",
        "-pca",
        action="store_true",
        help="If given, principal component analysis (PCA) is used "
        "to test various initializations for the point based registrations.")

    args = parser.parse_args()

    landmarks_fixed_nda = dr.DataReader.read_landmarks(args.fixed)
    landmarks_moving_nda = dr.DataReader.read_landmarks(args.moving)

    if args.pca:
        ph.print_subtitle("Use PCA to initialize registrations")
        pca_fixed = pca.PrincipalComponentAnalysis(landmarks_fixed_nda)
        pca_fixed.run()
        eigvec_fixed = pca_fixed.get_eigvec()
        mean_fixed = pca_fixed.get_mean()

        pca_moving = pca.PrincipalComponentAnalysis(landmarks_moving_nda)
        pca_moving.run()
        eigvec_moving = pca_moving.get_eigvec()
        mean_moving = pca_moving.get_mean()

        # test different initializations based on eigenvector orientations
        orientations = [
            [1, 1],
            [1, -1],
            [-1, 1],
            [-1, -1],
        ]
        error = np.inf
        for i_o, orientation in enumerate(orientations):
            eigvec_moving_o = np.array(eigvec_moving)
            eigvec_moving_o[:, 0] *= orientation[0]
            eigvec_moving_o[:, 1] *= orientation[1]

            # get right-handed coordinate system
            cross = np.cross(eigvec_moving_o[:, 0], eigvec_moving_o[:, 1])
            eigvec_moving_o[:, 2] = cross

            # transformation to align fixed with moving eigenbasis
            R = eigvec_moving_o.dot(eigvec_fixed.transpose())
            t = mean_moving - R.dot(mean_fixed)

            ph.print_info(
                "Registration based on PCA eigenvector initialization "
                "%d/%d ... " % (i_o + 1, len(orientations)),
                newline=False)
            reg = pycpd.rigid_registration(
                **{
                    "Y": landmarks_fixed_nda,
                    "X": landmarks_moving_nda,
                    "max_iterations": 100,
                    "R": R,
                    "t": t,
                })
            reg.register()
            params = reg.get_registration_parameters()
            scale, R, t = params
            error_o = reg.err
            print("done. Error: %.2f" % error_o)
            if error_o < error:
                error = error_o
                rotation_matrix_nda = np.array(R)
                translation_nda = np.array(t)
                ph.print_info("Currently best estimate")

    else:
        reg = pycpd.rigid_registration(
            **{
                "Y": landmarks_fixed_nda,
                "X": landmarks_moving_nda,
                "max_iterations": 100,
            })
        if args.verbose:
            fig = plt.figure()
            ax = fig.add_subplot(111, projection='3d')
            callback = partial(visualize, ax=ax)
        else:
            callback = None
        ph.print_info("Registration ... ", newline=False)
        reg.register(callback)
        if args.verbose:
            plt.show(block=False)
        # reg.register()
        scale, R, t = reg.get_registration_parameters()
        rotation_matrix_nda = R
        translation_nda = t
        print("done. Error: %.2f" % reg.err)

    rigid_transform_sitk = sitk.Euler3DTransform()
    rigid_transform_sitk.SetMatrix(rotation_matrix_nda.flatten())
    rigid_transform_sitk.SetTranslation(translation_nda)

    dw.DataWriter.write_transform(rigid_transform_sitk,
                                  args.output,
                                  verbose=True)

    elapsed_time_total = ph.stop_timing(time_start)
    ph.print_info("Computational Time: %s" % elapsed_time_total)

    return 0
Exemplo n.º 16
0
def main():

    time_start = ph.start_timing()

    # Set print options for numpy
    np.set_printoptions(precision=3)

    input_parser = InputArgparser(
        description="Volumetric MRI reconstruction framework to reconstruct "
        "an isotropic, high-resolution 3D volume from multiple stacks of 2D "
        "slices with motion correction. The resolution of the computed "
        "Super-Resolution Reconstruction (SRR) is given by the in-plane "
        "spacing of the selected target stack. A region of interest can be "
        "specified by providing a mask for the selected target stack. Only "
        "this region will then be reconstructed by the SRR algorithm which "
        "can substantially reduce the computational time.",
    )
    input_parser.add_filenames(required=True)
    input_parser.add_filenames_masks()
    input_parser.add_output(required=True)
    input_parser.add_suffix_mask(default="_mask")
    input_parser.add_target_stack(default=None)
    input_parser.add_search_angle(default=45)
    input_parser.add_multiresolution(default=0)
    input_parser.add_shrink_factors(default=[3, 2, 1])
    input_parser.add_smoothing_sigmas(default=[1.5, 1, 0])
    input_parser.add_sigma(default=1)
    input_parser.add_reconstruction_type(default="TK1L2")
    input_parser.add_iterations(default=15)
    input_parser.add_alpha(default=0.015)
    input_parser.add_alpha_first(default=0.2)
    input_parser.add_iter_max(default=10)
    input_parser.add_iter_max_first(default=5)
    input_parser.add_dilation_radius(default=3)
    input_parser.add_extra_frame_target(default=10)
    input_parser.add_bias_field_correction(default=0)
    input_parser.add_intensity_correction(default=1)
    input_parser.add_isotropic_resolution(default=1)
    input_parser.add_log_config(default=1)
    input_parser.add_subfolder_motion_correction()
    input_parser.add_write_motion_correction(default=1)
    input_parser.add_verbose(default=0)
    input_parser.add_two_step_cycles(default=3)
    input_parser.add_use_masks_srr(default=0)
    input_parser.add_boundary_stacks(default=[10, 10, 0])
    input_parser.add_metric(default="Correlation")
    input_parser.add_metric_radius(default=10)
    input_parser.add_reference()
    input_parser.add_reference_mask()
    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_interleave(default=3)
    input_parser.add_slice_thicknesses(default=None)
    input_parser.add_viewer(default="itksnap")
    input_parser.add_v2v_method(default="RegAladin")
    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_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."
    )
    input_parser.add_argument(
        "--sda", "-sda",
        action='store_true',
        help="If given, the volumetric reconstructions are performed using "
        "Scattered Data Approximation (Vercauteren et al., 2006). "
        "'alpha' is considered the final 'sigma' for the "
        "iterative adjustment. "
        "Recommended value is, e.g., --alpha 0.8"
    )
    input_parser.add_option(
        option_string="--transforms-history",
        type=int,
        help="Write entire history of applied slice motion correction "
        "transformations to motion correction output directory",
        default=0,
    )

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

    rejection_measure = "NCC"
    threshold_v2v = -2  # 0.3
    debug = False

    if args.v2v_method not in V2V_METHOD_OPTIONS:
        raise ValueError("v2v-method must be in {%s}" % (
            ", ".join(V2V_METHOD_OPTIONS)))

    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.alpha_first < args.alpha and not args.sda:
        raise ValueError("It must hold alpha-first >= alpha")

    if args.threshold_first > args.threshold:
        raise ValueError("It must hold threshold-first <= threshold")

    dir_output = os.path.dirname(args.output)
    ph.create_directory(dir_output)

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

    # --------------------------------Read Data--------------------------------
    ph.print_title("Read Data")
    data_reader = dr.MultipleImagesReader(
        file_paths=args.filenames,
        file_paths_masks=args.filenames_masks,
        suffix_mask=args.suffix_mask,
        stacks_slice_thicknesses=args.slice_thicknesses,
    )

    if len(args.boundary_stacks) is not 3:
        raise IOError(
            "Provide exactly three values for '--boundary-stacks' to define "
            "cropping in i-, j-, and k-dimension of the input stacks")

    data_reader.read_data()
    stacks = data_reader.get_data()
    ph.print_info("%d input stacks read for further processing" % len(stacks))

    if all(s.is_unity_mask() is True for s in stacks):
        ph.print_warning("No mask is provided! "
                         "Generated reconstruction space may be very big!")
        ph.print_warning("Consider using a mask to speed up computations")

        # args.extra_frame_target = 0
        # ph.wrint_warning("Overwritten: extra-frame-target set to 0")

    # Specify target stack for intensity correction and reconstruction space
    if args.target_stack is None:
        target_stack_index = 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")

    # ---------------------------Data Preprocessing---------------------------
    ph.print_title("Data Preprocessing")

    segmentation_propagator = segprop.SegmentationPropagation(
        # registration_method=regflirt.FLIRT(use_verbose=args.verbose),
        # registration_method=niftyreg.RegAladin(use_verbose=False),
        dilation_radius=args.dilation_radius,
        dilation_kernel="Ball",
    )

    data_preprocessing = dp.DataPreprocessing(
        stacks=stacks,
        segmentation_propagator=segmentation_propagator,
        use_cropping_to_mask=True,
        use_N4BiasFieldCorrector=args.bias_field_correction,
        target_stack_index=target_stack_index,
        boundary_i=args.boundary_stacks[0],
        boundary_j=args.boundary_stacks[1],
        boundary_k=args.boundary_stacks[2],
        unit="mm",
    )
    data_preprocessing.run()
    time_data_preprocessing = data_preprocessing.get_computational_time()

    # Get preprocessed stacks
    stacks = data_preprocessing.get_preprocessed_stacks()

    # Define reference/target stack for registration and reconstruction
    if args.reference is not None:
        reference = st.Stack.from_filename(
            file_path=args.reference,
            file_path_mask=args.reference_mask,
            extract_slices=False)

    else:
        reference = st.Stack.from_stack(stacks[target_stack_index])

    # ------------------------Volume-to-Volume Registration--------------------
    if len(stacks) > 1:

        if args.v2v_method == "FLIRT":
            # Define search angle ranges for FLIRT in all three dimensions
            search_angles = ["-searchr%s -%d %d" %
                             (x, args.search_angle, args.search_angle)
                             for x in ["x", "y", "z"]]
            options = (" ").join(search_angles)
            # options += " -noresample"

            vol_registration = regflirt.FLIRT(
                registration_type="Rigid",
                use_fixed_mask=True,
                use_moving_mask=True,
                options=options,
                use_verbose=False,
            )
        else:
            vol_registration = niftyreg.RegAladin(
                registration_type="Rigid",
                use_fixed_mask=True,
                use_moving_mask=True,
                # options="-ln 2 -voff",
                use_verbose=False,
            )
        v2vreg = pipeline.VolumeToVolumeRegistration(
            stacks=stacks,
            reference=reference,
            registration_method=vol_registration,
            verbose=debug,
            robust=args.v2v_robust,
        )
        v2vreg.run()
        stacks = v2vreg.get_stacks()
        time_registration = v2vreg.get_computational_time()

    else:
        time_registration = ph.get_zero_time()

    # ---------------------------Intensity Correction--------------------------
    if args.intensity_correction:
        ph.print_title("Intensity Correction")
        intensity_corrector = ic.IntensityCorrection()
        intensity_corrector.use_individual_slice_correction(False)
        intensity_corrector.use_reference_mask(True)
        intensity_corrector.use_stack_mask(True)
        intensity_corrector.use_verbose(False)

        for i, stack in enumerate(stacks):
            if i == target_stack_index:
                ph.print_info("Stack %d (%s): Reference image. Skipped." % (
                    i + 1, stack.get_filename()))
                continue
            else:
                ph.print_info("Stack %d (%s): Intensity Correction ... " % (
                    i + 1, stack.get_filename()), newline=False)
            intensity_corrector.set_stack(stack)
            intensity_corrector.set_reference(
                stacks[target_stack_index].get_resampled_stack(
                    resampling_grid=stack.sitk,
                    interpolator="NearestNeighbor",
                ))
            intensity_corrector.run_linear_intensity_correction()
            stacks[i] = intensity_corrector.get_intensity_corrected_stack()
            print("done (c1 = %g) " %
                  intensity_corrector.get_intensity_correction_coefficients())

    # ---------------------------Create first volume---------------------------
    time_tmp = ph.start_timing()

    # Isotropic resampling to define HR target space
    ph.print_title("Reconstruction Space Generation")
    HR_volume = reference.get_isotropically_resampled_stack(
        resolution=args.isotropic_resolution)
    ph.print_info(
        "Isotropic reconstruction space with %g mm resolution is created" %
        HR_volume.sitk.GetSpacing()[0])

    if args.reference is None:
        # Create joint image mask in target space
        joint_image_mask_builder = imb.JointImageMaskBuilder(
            stacks=stacks,
            target=HR_volume,
            dilation_radius=1,
        )
        joint_image_mask_builder.run()
        HR_volume = joint_image_mask_builder.get_stack()
        ph.print_info(
            "Isotropic reconstruction space is centered around "
            "joint stack masks. ")

        # Crop to space defined by mask (plus extra margin)
        HR_volume = HR_volume.get_cropped_stack_based_on_mask(
            boundary_i=args.extra_frame_target,
            boundary_j=args.extra_frame_target,
            boundary_k=args.extra_frame_target,
            unit="mm",
        )

        # Create first volume
        # If outlier rejection is activated, eliminate obvious outliers early
        # from stack and re-run SDA to get initial volume without them
        ph.print_title("First Estimate of HR Volume")
        if args.outlier_rejection and threshold_v2v > -1:
            ph.print_subtitle("SDA Approximation")
            SDA = sda.ScatteredDataApproximation(
                stacks, HR_volume, sigma=args.sigma)
            SDA.run()
            HR_volume = SDA.get_reconstruction()

            # Identify and reject outliers
            ph.print_subtitle("Eliminate slice outliers (%s < %g)" % (
                rejection_measure, threshold_v2v))
            outlier_rejector = outre.OutlierRejector(
                stacks=stacks,
                reference=HR_volume,
                threshold=threshold_v2v,
                measure=rejection_measure,
                verbose=True,
            )
            outlier_rejector.run()
            stacks = outlier_rejector.get_stacks()

        ph.print_subtitle("SDA Approximation Image")
        SDA = sda.ScatteredDataApproximation(
            stacks, HR_volume, sigma=args.sigma)
        SDA.run()
        HR_volume = SDA.get_reconstruction()

        ph.print_subtitle("SDA Approximation Image Mask")
        SDA = sda.ScatteredDataApproximation(
            stacks, HR_volume, sigma=args.sigma, sda_mask=True)
        SDA.run()
        # HR volume contains updated mask based on SDA
        HR_volume = SDA.get_reconstruction()

        HR_volume.set_filename(SDA.get_setting_specific_filename())

    time_reconstruction = ph.stop_timing(time_tmp)

    if args.verbose:
        tmp = list(stacks)
        tmp.insert(0, HR_volume)
        sitkh.show_stacks(tmp, segmentation=HR_volume, viewer=args.viewer)

    # -----------Two-step Slice-to-Volume Registration-Reconstruction----------
    if args.two_step_cycles > 0:

        # Slice-to-volume registration set-up
        if args.metric == "ANTSNeighborhoodCorrelation":
            metric_params = {"radius": args.metric_radius}
        else:
            metric_params = None
        registration = regsitk.SimpleItkRegistration(
            moving=HR_volume,
            use_fixed_mask=True,
            use_moving_mask=True,
            interpolator="Linear",
            metric=args.metric,
            metric_params=metric_params,
            use_multiresolution_framework=args.multiresolution,
            shrink_factors=args.shrink_factors,
            smoothing_sigmas=args.smoothing_sigmas,
            initializer_type="SelfGEOMETRY",
            optimizer="ConjugateGradientLineSearch",
            optimizer_params={
                "learningRate": 1,
                "numberOfIterations": 100,
                "lineSearchUpperLimit": 2,
            },
            scales_estimator="Jacobian",
            use_verbose=debug,
        )

        # Volumetric reconstruction set-up
        if args.sda:
            recon_method = sda.ScatteredDataApproximation(
                stacks,
                HR_volume,
                sigma=args.sigma,
                use_masks=args.use_masks_srr,
            )
            alpha_range = [args.sigma, args.alpha]
        else:
            recon_method = tk.TikhonovSolver(
                stacks=stacks,
                reconstruction=HR_volume,
                reg_type="TK1",
                minimizer="lsmr",
                alpha=args.alpha_first,
                iter_max=np.min([args.iter_max_first, args.iter_max]),
                verbose=True,
                use_masks=args.use_masks_srr,
            )
            alpha_range = [args.alpha_first, args.alpha]

        # Define the regularization parameters for the individual
        # reconstruction steps in the two-step cycles
        alphas = np.linspace(
            alpha_range[0], alpha_range[1], args.two_step_cycles)

        # Define outlier rejection threshold after each S2V-reg step
        thresholds = np.linspace(
            args.threshold_first, args.threshold, args.two_step_cycles)

        two_step_s2v_reg_recon = \
            pipeline.TwoStepSliceToVolumeRegistrationReconstruction(
                stacks=stacks,
                reference=HR_volume,
                registration_method=registration,
                reconstruction_method=recon_method,
                cycles=args.two_step_cycles,
                alphas=alphas[0:args.two_step_cycles - 1],
                outlier_rejection=args.outlier_rejection,
                threshold_measure=rejection_measure,
                thresholds=thresholds,
                interleave=args.interleave,
                viewer=args.viewer,
                verbose=args.verbose,
                use_hierarchical_registration=args.s2v_hierarchical,
            )
        two_step_s2v_reg_recon.run()
        HR_volume_iterations = \
            two_step_s2v_reg_recon.get_iterative_reconstructions()
        time_registration += \
            two_step_s2v_reg_recon.get_computational_time_registration()
        time_reconstruction += \
            two_step_s2v_reg_recon.get_computational_time_reconstruction()
        stacks = two_step_s2v_reg_recon.get_stacks()

    # no two-step s2v-registration/reconstruction iterations
    else:
        HR_volume_iterations = []

    # Write motion-correction results
    ph.print_title("Write Motion Correction Results")
    if args.write_motion_correction:
        dir_output_mc = os.path.join(
            dir_output, args.subfolder_motion_correction)
        ph.clear_directory(dir_output_mc)

        for stack in stacks:
            stack.write(
                dir_output_mc,
                write_stack=False,
                write_mask=False,
                write_slices=False,
                write_transforms=True,
                write_transforms_history=args.transforms_history,
            )

        if args.outlier_rejection:
            deleted_slices_dic = {}
            for i, stack in enumerate(stacks):
                deleted_slices = stack.get_deleted_slice_numbers()
                deleted_slices_dic[stack.get_filename()] = deleted_slices

            # check whether any stack was removed entirely
            stacks0 = data_preprocessing.get_preprocessed_stacks()
            if len(stacks) != len(stacks0):
                stacks_remain = [s.get_filename() for s in stacks]
                for stack in stacks0:
                    if stack.get_filename() in stacks_remain:
                        continue

                    # add info that all slices of this stack were rejected
                    deleted_slices = [
                        slice.get_slice_number()
                        for slice in stack.get_slices()
                    ]
                    deleted_slices_dic[stack.get_filename()] = deleted_slices
                    ph.print_info(
                        "All slices of stack '%s' were rejected entirely. "
                        "Information added." % stack.get_filename())

            ph.write_dictionary_to_json(
                deleted_slices_dic,
                os.path.join(
                    dir_output,
                    args.subfolder_motion_correction,
                    "rejected_slices.json"
                )
            )

    # ---------------------Final Volumetric Reconstruction---------------------
    ph.print_title("Final Volumetric Reconstruction")
    if args.sda:
        recon_method = sda.ScatteredDataApproximation(
            stacks,
            HR_volume,
            sigma=args.alpha,
            use_masks=args.use_masks_srr,
        )
    else:
        if args.reconstruction_type in ["TVL2", "HuberL2"]:
            recon_method = pd.PrimalDualSolver(
                stacks=stacks,
                reconstruction=HR_volume,
                reg_type="TV" if args.reconstruction_type == "TVL2" else "huber",
                iterations=args.iterations,
                use_masks=args.use_masks_srr,
            )
        else:
            recon_method = tk.TikhonovSolver(
                stacks=stacks,
                reconstruction=HR_volume,
                reg_type="TK1" if args.reconstruction_type == "TK1L2" else "TK0",
                use_masks=args.use_masks_srr,
            )
        recon_method.set_alpha(args.alpha)
        recon_method.set_iter_max(args.iter_max)
        recon_method.set_verbose(True)
    recon_method.run()
    time_reconstruction += recon_method.get_computational_time()
    HR_volume_final = recon_method.get_reconstruction()

    ph.print_subtitle("Final SDA Approximation Image Mask")
    SDA = sda.ScatteredDataApproximation(
        stacks, HR_volume_final, sigma=args.sigma, sda_mask=True)
    SDA.run()
    # HR volume contains updated mask based on SDA
    HR_volume_final = SDA.get_reconstruction()
    time_reconstruction += SDA.get_computational_time()

    elapsed_time_total = ph.stop_timing(time_start)

    # Write SRR result
    filename = recon_method.get_setting_specific_filename()
    HR_volume_final.set_filename(filename)
    dw.DataWriter.write_image(
        HR_volume_final.sitk,
        args.output,
        description=filename)
    dw.DataWriter.write_mask(
        HR_volume_final.sitk_mask,
        ph.append_to_filename(args.output, "_mask"),
        description=SDA.get_setting_specific_filename())

    HR_volume_iterations.insert(0, HR_volume_final)
    for stack in stacks:
        HR_volume_iterations.append(stack)

    if args.verbose:
        sitkh.show_stacks(
            HR_volume_iterations,
            segmentation=HR_volume_final,
            viewer=args.viewer,
        )

    # Summary
    ph.print_title("Summary")
    exe_file_info = os.path.basename(os.path.abspath(__file__)).split(".")[0]
    print("%s | Computational Time for Data Preprocessing: %s" %
          (exe_file_info, time_data_preprocessing))
    print("%s | Computational Time for Registrations: %s" %
          (exe_file_info, time_registration))
    print("%s | Computational Time for Reconstructions: %s" %
          (exe_file_info, time_reconstruction))
    print("%s | Computational Time for Entire Reconstruction Pipeline: %s" %
          (exe_file_info, elapsed_time_total))

    ph.print_line_separator()

    return 0
Exemplo n.º 17
0
def main():

    time_start = ph.start_timing()

    # Set print options for numpy
    np.set_printoptions(precision=3)

    # Read input
    input_parser = InputArgparser(
        description="Volumetric MRI reconstruction framework to reconstruct "
        "an isotropic, high-resolution 3D volume from multiple stacks of 2D "
        "slices with motion correction. The resolution of the computed "
        "Super-Resolution Reconstruction (SRR) is given by the in-plane "
        "spacing of the selected target stack. A region of interest can be "
        "specified by providing a mask for the selected target stack. Only "
        "this region will then be reconstructed by the SRR algorithm which "
        "can substantially reduce the computational time.", )
    input_parser.add_dir_input()
    input_parser.add_filenames()
    input_parser.add_dir_output(required=True)
    input_parser.add_suffix_mask(default="_mask")
    input_parser.add_target_stack_index(default=0)
    input_parser.add_search_angle(default=90)
    input_parser.add_multiresolution(default=0)
    input_parser.add_shrink_factors(default=[2, 1])
    input_parser.add_smoothing_sigmas(default=[1, 0])
    input_parser.add_sigma(default=0.9)
    input_parser.add_reconstruction_type(default="TK1L2")
    input_parser.add_iterations(default=15)
    input_parser.add_alpha(default=0.02)
    input_parser.add_alpha_first(default=0.05)
    input_parser.add_iter_max(default=10)
    input_parser.add_iter_max_first(default=5)
    input_parser.add_dilation_radius(default=3)
    input_parser.add_extra_frame_target(default=10)
    input_parser.add_bias_field_correction(default=0)
    input_parser.add_intensity_correction(default=0)
    input_parser.add_isotropic_resolution(default=None)
    input_parser.add_log_script_execution(default=1)
    input_parser.add_subfolder_motion_correction()
    input_parser.add_provide_comparison(default=0)
    input_parser.add_subfolder_comparison()
    input_parser.add_write_motion_correction(default=1)
    input_parser.add_verbose(default=0)
    input_parser.add_two_step_cycles(default=3)
    input_parser.add_use_masks_srr(default=1)
    input_parser.add_boundary_stacks(default=[10, 10, 0])
    input_parser.add_reference()
    input_parser.add_reference_mask()

    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__))

    # Use FLIRT for volume-to-volume reg. step. Otherwise, RegAladin is used.
    use_flirt_for_v2v_registration = True

    # --------------------------------Read Data--------------------------------
    ph.print_title("Read Data")

    # Neither '--dir-input' nor '--filenames' was specified
    if args.filenames is not None and args.dir_input is not None:
        raise IOError("Provide input by either '--dir-input' or '--filenames' "
                      "but not both together")

    # '--dir-input' specified
    elif args.dir_input is not None:
        data_reader = dr.ImageDirectoryReader(args.dir_input,
                                              suffix_mask=args.suffix_mask)

    # '--filenames' specified
    elif args.filenames is not None:
        data_reader = dr.MultipleImagesReader(args.filenames,
                                              suffix_mask=args.suffix_mask)

    else:
        raise IOError("Provide input by either '--dir-input' or '--filenames'")

    if len(args.boundary_stacks) is not 3:
        raise IOError(
            "Provide exactly three values for '--boundary-stacks' to define "
            "cropping in i-, j-, and k-dimension of the input stacks")

    data_reader.read_data()
    stacks = data_reader.get_data()
    ph.print_info("%d input stacks read for further processing" % len(stacks))

    if all(s.is_unity_mask() is True for s in stacks):
        ph.print_warning("No mask is provided! "
                         "Generated reconstruction space may be very big!")

    # ---------------------------Data Preprocessing---------------------------
    ph.print_title("Data Preprocessing")

    segmentation_propagator = segprop.SegmentationPropagation(
        # registration_method=regflirt.FLIRT(use_verbose=args.verbose),
        dilation_radius=args.dilation_radius,
        dilation_kernel="Ball",
    )

    data_preprocessing = dp.DataPreprocessing(
        stacks=stacks,
        segmentation_propagator=segmentation_propagator,
        use_cropping_to_mask=True,
        use_N4BiasFieldCorrector=args.bias_field_correction,
        use_intensity_correction=args.intensity_correction,
        target_stack_index=args.target_stack_index,
        boundary_i=args.boundary_stacks[0],
        boundary_j=args.boundary_stacks[1],
        boundary_k=args.boundary_stacks[2],
        unit="mm",
    )
    data_preprocessing.run()
    time_data_preprocessing = data_preprocessing.get_computational_time()

    # Get preprocessed stacks
    stacks = data_preprocessing.get_preprocessed_stacks()

    # Define reference/target stack for registration and reconstruction
    if args.reference is not None:
        reference = st.Stack.from_filename(file_path=args.reference,
                                           file_path_mask=args.reference_mask,
                                           extract_slices=False)

    else:
        reference = st.Stack.from_stack(stacks[args.target_stack_index])

    # ------------------------Volume-to-Volume Registration--------------------
    if args.two_step_cycles > 0:
        # Define search angle ranges for FLIRT in all three dimensions
        search_angles = [
            "-searchr%s -%d %d" % (x, args.search_angle, args.search_angle)
            for x in ["x", "y", "z"]
        ]
        search_angles = (" ").join(search_angles)

        if use_flirt_for_v2v_registration:
            vol_registration = regflirt.FLIRT(
                registration_type="Rigid",
                use_fixed_mask=True,
                use_moving_mask=True,
                options=search_angles,
                use_verbose=False,
            )
        else:
            vol_registration = niftyreg.RegAladin(
                registration_type="Rigid",
                use_fixed_mask=True,
                use_moving_mask=True,
                use_verbose=False,
            )
        v2vreg = pipeline.VolumeToVolumeRegistration(
            stacks=stacks,
            reference=reference,
            registration_method=vol_registration,
            verbose=args.verbose,
        )
        v2vreg.run()
        stacks = v2vreg.get_stacks()
        time_registration = v2vreg.get_computational_time()

    else:
        time_registration = ph.get_zero_time()

    # ---------------------------Create first volume---------------------------
    time_tmp = ph.start_timing()

    # Isotropic resampling to define HR target space
    ph.print_title("Reconstruction Space Generation")
    HR_volume = reference.get_isotropically_resampled_stack(
        resolution=args.isotropic_resolution)
    ph.print_info(
        "Isotropic reconstruction space with %g mm resolution is created" %
        HR_volume.sitk.GetSpacing()[0])

    if args.reference is None:
        # Create joint image mask in target space
        joint_image_mask_builder = imb.JointImageMaskBuilder(
            stacks=stacks,
            target=HR_volume,
            dilation_radius=1,
        )
        joint_image_mask_builder.run()
        HR_volume = joint_image_mask_builder.get_stack()
        ph.print_info("Isotropic reconstruction space is centered around "
                      "joint stack masks. ")

        # Crop to space defined by mask (plus extra margin)
        HR_volume = HR_volume.get_cropped_stack_based_on_mask(
            boundary_i=args.extra_frame_target,
            boundary_j=args.extra_frame_target,
            boundary_k=args.extra_frame_target,
            unit="mm",
        )

        # Scattered Data Approximation to get first estimate of HR volume
        ph.print_title("First Estimate of HR Volume")
        SDA = sda.ScatteredDataApproximation(stacks,
                                             HR_volume,
                                             sigma=args.sigma)
        SDA.run()
        HR_volume = SDA.get_reconstruction()

    time_reconstruction = ph.stop_timing(time_tmp)

    if args.verbose:
        tmp = list(stacks)
        tmp.insert(0, HR_volume)
        sitkh.show_stacks(tmp, segmentation=HR_volume)

    # ----------------Two-step Slice-to-Volume Registration SRR----------------
    SRR = tk.TikhonovSolver(
        stacks=stacks,
        reconstruction=HR_volume,
        reg_type="TK1",
        minimizer="lsmr",
        alpha=args.alpha_first,
        iter_max=args.iter_max_first,
        verbose=True,
        use_masks=args.use_masks_srr,
    )

    if args.two_step_cycles > 0:

        registration = regsitk.SimpleItkRegistration(
            moving=HR_volume,
            use_fixed_mask=True,
            use_moving_mask=True,
            use_verbose=args.verbose,
            interpolator="Linear",
            metric="Correlation",
            use_multiresolution_framework=args.multiresolution,
            shrink_factors=args.shrink_factors,
            smoothing_sigmas=args.smoothing_sigmas,
            initializer_type="SelfGEOMETRY",
            optimizer="ConjugateGradientLineSearch",
            optimizer_params={
                "learningRate": 1,
                "numberOfIterations": 100,
                "lineSearchUpperLimit": 2,
            },
            scales_estimator="Jacobian",
        )
        two_step_s2v_reg_recon = \
            pipeline.TwoStepSliceToVolumeRegistrationReconstruction(
                stacks=stacks,
                reference=HR_volume,
                registration_method=registration,
                reconstruction_method=SRR,
                cycles=args.two_step_cycles,
                alpha_range=[args.alpha_first, args.alpha],
                verbose=args.verbose,
            )
        two_step_s2v_reg_recon.run()
        HR_volume_iterations = \
            two_step_s2v_reg_recon.get_iterative_reconstructions()
        time_registration += \
            two_step_s2v_reg_recon.get_computational_time_registration()
        time_reconstruction += \
            two_step_s2v_reg_recon.get_computational_time_reconstruction()
    else:
        HR_volume_iterations = []

    # Write motion-correction results
    if args.write_motion_correction:
        for stack in stacks:
            stack.write(
                os.path.join(args.dir_output,
                             args.subfolder_motion_correction),
                write_mask=True,
                write_slices=True,
                write_transforms=True,
                suffix_mask=args.suffix_mask,
            )

    # ------------------Final Super-Resolution Reconstruction------------------
    ph.print_title("Final Super-Resolution Reconstruction")
    if args.reconstruction_type in ["TVL2", "HuberL2"]:
        SRR = pd.PrimalDualSolver(
            stacks=stacks,
            reconstruction=HR_volume,
            reg_type="TV" if args.reconstruction_type == "TVL2" else "huber",
            iterations=args.iterations,
        )
    else:
        SRR = tk.TikhonovSolver(
            stacks=stacks,
            reconstruction=HR_volume,
            reg_type="TK1" if args.reconstruction_type == "TK1L2" else "TK0",
            use_masks=args.use_masks_srr,
        )
    SRR.set_alpha(args.alpha)
    SRR.set_iter_max(args.iter_max)
    SRR.set_verbose(True)
    SRR.run()
    time_reconstruction += SRR.get_computational_time()

    elapsed_time_total = ph.stop_timing(time_start)

    # Write SRR result
    HR_volume_final = SRR.get_reconstruction()
    HR_volume_final.set_filename(SRR.get_setting_specific_filename())
    HR_volume_final.write(args.dir_output,
                          write_mask=True,
                          suffix_mask=args.suffix_mask)

    HR_volume_iterations.insert(0, HR_volume_final)
    for stack in stacks:
        HR_volume_iterations.append(stack)

    if args.verbose and not args.provide_comparison:
        sitkh.show_stacks(HR_volume_iterations, segmentation=HR_volume)
    # HR_volume_final.show()

    # Show SRR together with linearly resampled input data.
    # Additionally, a script is generated to open files
    if args.provide_comparison:
        sitkh.show_stacks(
            HR_volume_iterations,
            segmentation=HR_volume,
            show_comparison_file=args.provide_comparison,
            dir_output=os.path.join(args.dir_output,
                                    args.subfolder_comparison),
        )

    # Summary
    ph.print_title("Summary")
    print("Computational Time for Data Preprocessing: %s" %
          (time_data_preprocessing))
    print("Computational Time for Registrations: %s" % (time_registration))
    print("Computational Time for Reconstructions: %s" % (time_reconstruction))
    print("Computational Time for Entire Reconstruction Pipeline: %s" %
          (elapsed_time_total))

    ph.print_line_separator()

    return 0
Exemplo n.º 18
0
def main():

    time_start = ph.start_timing()

    np.set_printoptions(precision=3)

    input_parser = InputArgparser(
        description="Perform (linear) intensity correction across "
        "stacks/images given a reference stack/image", )
    input_parser.add_filenames(required=True)
    input_parser.add_dir_output(required=True)
    input_parser.add_reference(required=True)
    input_parser.add_suffix_mask(default="_mask")
    input_parser.add_search_angle(default=180)
    input_parser.add_prefix_output(default="IC_")
    input_parser.add_log_config(default=1)
    input_parser.add_option(
        option_string="--registration",
        type=int,
        help="Turn on/off registration from image to reference prior to "
        "intensity correction.",
        default=0)
    input_parser.add_verbose(default=0)

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

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

    if args.reference in args.filenames:
        args.filenames.remove(args.reference)

    # Read data
    data_reader = dr.MultipleImagesReader(args.filenames,
                                          suffix_mask=args.suffix_mask,
                                          extract_slices=False)
    data_reader.read_data()
    stacks = data_reader.get_data()

    data_reader = dr.MultipleImagesReader([args.reference],
                                          suffix_mask=args.suffix_mask,
                                          extract_slices=False)
    data_reader.read_data()
    reference = data_reader.get_data()[0]

    if args.registration:
        # Define search angle ranges for FLIRT in all three dimensions
        search_angles = [
            "-searchr%s -%d %d" % (x, args.search_angle, args.search_angle)
            for x in ["x", "y", "z"]
        ]
        search_angles = (" ").join(search_angles)
        registration = regflirt.FLIRT(
            moving=reference,
            registration_type="Rigid",
            use_fixed_mask=True,
            use_moving_mask=True,
            options=search_angles,
            use_verbose=False,
        )

    # Perform Intensity Correction
    ph.print_title("Perform Intensity Correction")
    intensity_corrector = ic.IntensityCorrection(
        use_reference_mask=True,
        use_individual_slice_correction=False,
        prefix_corrected=args.prefix_output,
        use_verbose=False,
    )
    stacks_corrected = [None] * len(stacks)
    for i, stack in enumerate(stacks):
        if args.registration:
            ph.print_info("Image %d/%d: Registration ... " %
                          (i + 1, len(stacks)),
                          newline=False)
            registration.set_fixed(stack)
            registration.run()
            transform_sitk = registration.get_registration_transform_sitk()
            stack.update_motion_correction(transform_sitk)
            print("done")

        ph.print_info("Image %d/%d: Intensity Correction ... " %
                      (i + 1, len(stacks)),
                      newline=False)

        ref = reference.get_resampled_stack(stack.sitk)
        ref = st.Stack.from_sitk_image(image_sitk=ref.sitk,
                                       image_sitk_mask=stack.sitk_mask *
                                       ref.sitk_mask,
                                       filename=reference.get_filename())
        intensity_corrector.set_stack(stack)
        intensity_corrector.set_reference(ref)
        intensity_corrector.run_linear_intensity_correction()
        # intensity_corrector.run_affine_intensity_correction()
        stacks_corrected[i] = \
            intensity_corrector.get_intensity_corrected_stack()
        print("done (c1 = %g) " %
              intensity_corrector.get_intensity_correction_coefficients())

        # Write Data
        stacks_corrected[i].write(args.dir_output,
                                  write_mask=True,
                                  suffix_mask=args.suffix_mask)

        if args.verbose:
            sitkh.show_stacks(
                [
                    reference,
                    stacks_corrected[i],
                    # stacks[i],
                ],
                segmentation=stacks_corrected[i])
            # ph.pause()

    # Write reference too (although not intensity corrected)
    reference.write(args.dir_output,
                    filename=args.prefix_output + reference.get_filename(),
                    write_mask=True,
                    suffix_mask=args.suffix_mask)

    elapsed_time = ph.stop_timing(time_start)

    ph.print_title("Summary")
    print("Computational Time for Intensity Correction(s): %s" %
          (elapsed_time))

    return 0
Exemplo n.º 19
0
def main():

    time_start = ph.start_timing()

    np.set_printoptions(precision=3)

    input_parser = InputArgparser(
        description="Perform Bias Field correction on images based on N4ITK.",
    )
    input_parser.add_filenames(required=True)
    input_parser.add_dir_output(required=True)
    input_parser.add_suffix_mask(default="_mask")
    input_parser.add_prefix_output(default="N4ITK_")
    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_script_execution(default=1)
    input_parser.add_verbose(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__))

    # Read data
    data_reader = dr.MultipleImagesReader(args.filenames,
                                          suffix_mask=args.suffix_mask)
    data_reader.read_data()
    stacks = data_reader.get_data()

    # Perform Bias Field Correction
    ph.print_title("Perform Bias Field Correction")
    bias_field_corrector = n4itk.N4BiasFieldCorrection(
        convergence_threshold=args.convergence_threshold,
        spline_order=args.spline_order,
        wiener_filter_noise=args.wiener_filter_noise,
        bias_field_fwhm=args.bias_field_fwhm,
        prefix_corrected=args.prefix_output,
    )
    stacks_corrected = [None] * len(stacks)
    for i, stack in enumerate(stacks):
        ph.print_info("Image %d/%d: N4ITK Bias Field Correction ... " %
                      (i + 1, len(stacks)),
                      newline=False)
        bias_field_corrector.set_stack(stack)
        bias_field_corrector.run_bias_field_correction()
        stacks_corrected[i] = \
            bias_field_corrector.get_bias_field_corrected_stack()
        print("done")
        ph.print_info("Image %d/%d: Computational time = %s" %
                      (i + 1, len(stacks),
                       bias_field_corrector.get_computational_time()))

        # Write Data
        stacks_corrected[i].write(args.dir_output,
                                  write_mask=True,
                                  suffix_mask=args.suffix_mask)

        if args.verbose:
            sitkh.show_stacks([stacks[i], stacks_corrected[i]],
                              segmentation=stacks[i])

    elapsed_time = ph.stop_timing(time_start)

    ph.print_title("Summary")
    print("Computational Time for Bias Field Correction(s): %s" %
          (elapsed_time))

    return 0
Exemplo n.º 20
0
def main():

    time_start = ph.start_timing()

    # Set print options for numpy
    np.set_printoptions(precision=3)

    # Read input
    input_parser = InputArgparser(
        description="Script to study reconstruction parameters and their "
        "impact on the volumetric reconstruction quality.",
    )
    input_parser.add_dir_input()
    input_parser.add_filenames()
    input_parser.add_image_selection()
    input_parser.add_dir_output(required=True)
    input_parser.add_suffix_mask(default="_mask")
    input_parser.add_reconstruction_space()
    input_parser.add_reference(
        help="Path to reference NIfTI image file. If given the volumetric "
        "reconstructed is performed in this physical space. "
        "Either a reconstruction space or a reference must be provided",
        required=False)
    input_parser.add_reference_mask(default=None)
    input_parser.add_study_name()
    input_parser.add_reconstruction_type(default="TK1L2")
    input_parser.add_measures(default=["PSNR", "RMSE", "SSIM", "NCC", "NMI"])
    input_parser.add_tv_solver(default="PD")
    input_parser.add_iterations(default=50)
    input_parser.add_rho(default=0.1)
    input_parser.add_iter_max(default=10)
    input_parser.add_minimizer(default="lsmr")
    input_parser.add_alpha(default=0.01)
    input_parser.add_data_loss(default="linear")
    input_parser.add_data_loss_scale(default=1)
    input_parser.add_log_script_execution(default=1)
    input_parser.add_verbose(default=1)

    # Range for parameter sweeps
    input_parser.add_alpha_range(default=[0.001, 0.05, 20])  # TK1L2
    # input_parser.add_alpha_range(default=[0.001, 0.003, 10])  # TVL2, HuberL2
    input_parser.add_data_losses(
        # default=["linear", "arctan"]
    )
    input_parser.add_data_loss_scale_range(
        # default=[0.1, 1.5, 2]
    )

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

    if args.reference is None and args.reconstruction_space is None:
        raise IOError("Either reference (--reference) or reconstruction space "
                      "(--reconstruction-space) must be provided.")

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

    # --------------------------------Read Data--------------------------------
    ph.print_title("Read Data")

    # Neither '--dir-input' nor '--filenames' was specified
    if args.filenames is not None and args.dir_input is not None:
        raise IOError(
            "Provide input by either '--dir-input' or '--filenames' "
            "but not both together")

    # '--dir-input' specified
    elif args.dir_input is not None:
        data_reader = dr.ImageSlicesDirectoryReader(
            path_to_directory=args.dir_input,
            suffix_mask=args.suffix_mask,
            image_selection=args.image_selection)

    # '--filenames' specified
    elif args.filenames is not None:
        data_reader = dr.MultipleImagesReader(
            args.filenames, suffix_mask=args.suffix_mask)

    else:
        raise IOError(
            "Provide input by either '--dir-input' or '--filenames'")

    data_reader.read_data()
    stacks = data_reader.get_data()
    ph.print_info("%d input stacks read for further processing" % len(stacks))

    if args.reference is not None:
        reference = st.Stack.from_filename(
            file_path=args.reference,
            file_path_mask=args.reference_mask,
            extract_slices=False)

        reconstruction_space = stacks[0].get_resampled_stack(reference.sitk)
        reconstruction_space = \
            reconstruction_space.get_stack_multiplied_with_mask()
        x_ref = sitk.GetArrayFromImage(reference.sitk).flatten()
        x_ref_mask = sitk.GetArrayFromImage(reference.sitk_mask).flatten()

    else:
        reconstruction_space = st.Stack.from_filename(
            file_path=args.reconstruction_space,
            extract_slices=False)
        reconstruction_space = stacks[0].get_resampled_stack(
            reconstruction_space.sitk)
        reconstruction_space = \
            reconstruction_space.get_stack_multiplied_with_mask()
        x_ref = None
        x_ref_mask = None

    # ----------------------------Set Up Parameters----------------------------
    parameters = {}
    parameters["alpha"] = np.linspace(
        args.alpha_range[0], args.alpha_range[1], int(args.alpha_range[2]))
    if args.data_losses is not None:
        parameters["data_loss"] = args.data_losses
    if args.data_loss_scale_range is not None:
        parameters["data_loss_scale"] = np.linspace(
            args.data_loss_scale_range[0],
            args.data_loss_scale_range[1],
            int(args.data_loss_scale_range[2]))

    # --------------------------Set Up Parameter Study-------------------------
    if args.study_name is None:
        name = args.reconstruction_type
    else:
        name = args.study_name

    reconstruction_info = {
        "shape": reconstruction_space.sitk.GetSize()[::-1],
        "origin": reconstruction_space.sitk.GetOrigin(),
        "spacing": reconstruction_space.sitk.GetSpacing(),
        "direction": reconstruction_space.sitk.GetDirection(),
    }

    # Create Tikhonov solver from which all information can be extracted
    # (also for other reconstruction types)
    tmp = tk.TikhonovSolver(
        stacks=stacks,
        reconstruction=reconstruction_space,
        alpha=args.alpha,
        iter_max=args.iter_max,
        data_loss=args.data_loss,
        data_loss_scale=args.data_loss_scale,
        reg_type="TK1",
        minimizer=args.minimizer,
        verbose=args.verbose,
    )
    solver = tmp.get_solver()

    parameter_study_interface = \
        deconv_interface.DeconvolutionParameterStudyInterface(
            A=solver.get_A(),
            A_adj=solver.get_A_adj(),
            D=solver.get_B(),
            D_adj=solver.get_B_adj(),
            b=solver.get_b(),
            x0=solver.get_x0(),
            alpha=solver.get_alpha(),
            x_scale=solver.get_x_scale(),
            data_loss=solver.get_data_loss(),
            data_loss_scale=solver.get_data_loss_scale(),
            iter_max=solver.get_iter_max(),
            minimizer=solver.get_minimizer(),
            iterations=args.iterations,
            measures=args.measures,
            dimension=3,
            L2=16./reconstruction_space.sitk.GetSpacing()[0]**2,
            reconstruction_type=args.reconstruction_type,
            rho=args.rho,
            dir_output=args.dir_output,
            parameters=parameters,
            name=name,
            reconstruction_info=reconstruction_info,
            x_ref=x_ref,
            x_ref_mask=x_ref_mask,
            tv_solver=args.tv_solver,
            verbose=args.verbose,
        )
    parameter_study_interface.set_up_parameter_study()
    parameter_study = parameter_study_interface.get_parameter_study()

    # Run parameter study
    parameter_study.run()

    print("\nComputational time for Deconvolution Parameter Study %s: %s" %
          (name, parameter_study.get_computational_time()))

    return 0
Exemplo n.º 21
0
    def from_motion_score(cls, file_paths, file_paths_masks):

        if len(file_paths) != len(file_paths_masks):
            raise ValueError("Number of provided images and masks must match")

        t0 = ph.start_timing()
        tse = cls()

        volumes = np.array([
            TargetStackEstimator._compute_volume(f) for f in file_paths_masks
        ])

        # only allow stacks with minimum volume, i.e. anatomical/brain coverage
        vol_min = 0.7 * np.median(volumes)
        indices = [i for i in range(len(volumes)) if volumes[i] > vol_min]

        # read all eligible stacks
        stacks = [
            st.Stack.from_filename(
                file_path=file_paths[i],
                file_path_mask=file_paths_masks[i],
                extract_slices=False,
            ) for i in indices
        ]

        # crop stack to bounding box of mask
        stacks = [s.get_cropped_stack_based_on_mask() for s in stacks]

        # debug
        # for i_stack, stack in enumerate(stacks):
        #     stack.show(label=str(indices[i_stack]))

        # compute motion scores of eligible stacks
        motion_scores = [None] * len(indices)
        for i_stack in range(len(indices)):

            # compute singular values
            s = TargetStackEstimator._compute_singular_values(stacks[i_stack])

            # compute motion score
            motion_scores[i_stack] = tse._compute_motion_score[tse._mode](s)

        # select stack with minimum motion (score)
        selection_best = np.argmin(motion_scores)

        # reference back to input file_paths index
        target_stack_index = indices[selection_best]

        tse._target_stack_index = target_stack_index

        # computational time
        tse._computational_time = ph.stop_timing(t0)

        # debug
        # print(indices, len(indices), len(file_paths))
        # print("Best: %d" % target_stack_index)
        # print(motion_scores)
        # print(tse.get_computational_time())
        # ph.killall_itksnap()

        return tse
Exemplo n.º 22
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
Exemplo n.º 23
0
def main():

    time_start = ph.start_timing()

    # Set print options for numpy
    np.set_printoptions(precision=3)

    # Read input
    input_parser = InputArgparser(
        description="Volumetric MRI reconstruction framework to reconstruct "
        "an isotropic, high-resolution 3D volume from multiple "
        "motion-corrected (or static) stacks of low-resolution slices.", )
    input_parser.add_dir_input()
    input_parser.add_filenames()
    input_parser.add_image_selection()
    input_parser.add_dir_output(required=True)
    input_parser.add_prefix_output(default="SRR_")
    input_parser.add_suffix_mask(default="_mask")
    input_parser.add_target_stack_index(default=0)
    input_parser.add_extra_frame_target(default=10)
    input_parser.add_isotropic_resolution(default=None)
    input_parser.add_reconstruction_space(default=None)
    input_parser.add_minimizer(default="lsmr")
    input_parser.add_iter_max(default=10)
    input_parser.add_reconstruction_type(default="TK1L2")
    input_parser.add_data_loss(default="linear")
    input_parser.add_data_loss_scale(default=1)
    input_parser.add_alpha(default=0.02  # TK1L2
                           # default=0.006  #TVL2, HuberL2
                           )
    input_parser.add_rho(default=0.5)
    input_parser.add_tv_solver(default="PD")
    input_parser.add_pd_alg_type(default="ALG2")
    input_parser.add_iterations(default=15)
    input_parser.add_subfolder_comparison()
    input_parser.add_provide_comparison(default=0)
    input_parser.add_log_script_execution(default=1)
    input_parser.add_verbose(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__))

    # --------------------------------Read Data--------------------------------
    ph.print_title("Read Data")

    # Neither '--dir-input' nor '--filenames' was specified
    if args.filenames is not None and args.dir_input is not None:
        raise IOError("Provide input by either '--dir-input' or '--filenames' "
                      "but not both together")

    # '--dir-input' specified
    elif args.dir_input is not None:
        data_reader = dr.ImageSlicesDirectoryReader(
            path_to_directory=args.dir_input,
            suffix_mask=args.suffix_mask,
            image_selection=args.image_selection)

    # '--filenames' specified
    elif args.filenames is not None:
        data_reader = dr.MultipleImagesReader(args.filenames,
                                              suffix_mask=args.suffix_mask)

    else:
        raise IOError("Provide input by either '--dir-input' or '--filenames'")

    if args.reconstruction_type not in ["TK1L2", "TVL2", "HuberL2"]:
        raise IOError("Reconstruction type unknown")

    data_reader.read_data()
    stacks = data_reader.get_data()
    ph.print_info("%d input stacks read for further processing" % len(stacks))

    # Reconstruction space is given isotropically resampled target stack
    if args.reconstruction_space is None:
        recon0 = \
            stacks[args.target_stack_index].get_isotropically_resampled_stack(
                resolution=args.isotropic_resolution,
                extra_frame=args.extra_frame_target)

    # Reconstruction space was provided by user
    else:
        recon0 = st.Stack.from_filename(args.reconstruction_space,
                                        extract_slices=False)

        # Change resolution for isotropic resolution if provided by user
        if args.isotropic_resolution is not None:
            recon0 = recon0.get_isotropically_resampled_stack(
                args.isotropic_resolution)

        # Use image information of selected target stack as recon0 serves
        # as initial value for reconstruction
        recon0 = \
            stacks[args.target_stack_index].get_resampled_stack(recon0.sitk)
        recon0 = recon0.get_stack_multiplied_with_mask()

    if args.reconstruction_type in ["TVL2", "HuberL2"]:
        ph.print_title("Compute Initial value for %s" %
                       args.reconstruction_type)
    SRR0 = tk.TikhonovSolver(
        stacks=stacks,
        reconstruction=recon0,
        alpha=args.alpha,
        iter_max=args.iter_max,
        reg_type="TK1",
        minimizer=args.minimizer,
        data_loss=args.data_loss,
        data_loss_scale=args.data_loss_scale,
        # verbose=args.verbose,
    )
    SRR0.run()

    recon = SRR0.get_reconstruction()
    recon.set_filename(SRR0.get_setting_specific_filename(args.prefix_output))
    recon.write(args.dir_output)

    # List to store SRRs
    recons = []
    for i in range(0, len(stacks)):
        recons.append(stacks[i])
    recons.insert(0, recon)

    if args.reconstruction_type in ["TVL2", "HuberL2"]:
        ph.print_title("Compute %s reconstruction" % args.reconstruction_type)
        if args.tv_solver == "ADMM":
            SRR = admm.ADMMSolver(
                stacks=stacks,
                reconstruction=st.Stack.from_stack(SRR0.get_reconstruction()),
                minimizer=args.minimizer,
                alpha=args.alpha,
                iter_max=args.iter_max,
                rho=args.rho,
                data_loss=args.data_loss,
                iterations=args.iterations,
                verbose=args.verbose,
            )
            SRR.run()
            recon = SRR.get_reconstruction()
            recon.set_filename(
                SRR.get_setting_specific_filename(args.prefix_output))
            recons.insert(0, recon)

            recon.write(args.dir_output)

        else:

            SRR = pd.PrimalDualSolver(
                stacks=stacks,
                reconstruction=st.Stack.from_stack(SRR0.get_reconstruction()),
                minimizer=args.minimizer,
                alpha=args.alpha,
                iter_max=args.iter_max,
                iterations=args.iterations,
                alg_type=args.pd_alg_type,
                reg_type="TV"
                if args.reconstruction_type == "TVL2" else "huber",
                data_loss=args.data_loss,
                verbose=args.verbose,
            )
            SRR.run()
            recon = SRR.get_reconstruction()
            recon.set_filename(
                SRR.get_setting_specific_filename(args.prefix_output))
            recons.insert(0, recon)

            recon.write(args.dir_output)

    if args.verbose and not args.provide_comparison:
        sitkh.show_stacks(recons)

    # Show SRR together with linearly resampled input data.
    # Additionally, a script is generated to open files
    if args.provide_comparison:
        sitkh.show_stacks(
            recons,
            show_comparison_file=args.provide_comparison,
            dir_output=os.path.join(args.dir_output,
                                    args.subfolder_comparison),
        )

    ph.print_line_separator()

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

    return 0
Exemplo n.º 24
0
def main():
    time_start = ph.start_timing()

    np.set_printoptions(precision=3)

    input_parser = InputArgparser(
        description="Perform automatic brain masking using "
        "fetal_brain_seg, part of the MONAIfbs package "
        "(https://github.com/gift-surg/MONAIfbs). ",
    )
    input_parser.add_filenames(required=True)
    input_parser.add_filenames_masks(required=False)
    input_parser.add_dir_output(required=False)
    input_parser.add_verbose(default=0)
    input_parser.add_log_config(default=0)
    input_parser.add_option(
        option_string="--neuroimage-legacy-seg",
        type=int,
        required=False,
        default=0,
        help="If set to 1, use the legacy method for fetal brain segmentation "
             "i.e. the two-step approach proposed in Ebner, Wang et al "
             "NeuroImage (2020)"
    )

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

    if args.neuroimage_legacy_seg:
        try:
            DIR_FETAL_BRAIN_SEG = os.environ["FETAL_BRAIN_SEG"]
        except KeyError as e:
            raise RuntimeError(
                "Environment variable FETAL_BRAIN_SEG is not specified. "
                "Specify the root directory of fetal_brain_seg "
                "(https://github.com/gift-surg/fetal_brain_seg) "
                "using "
                "'export FETAL_BRAIN_SEG=path_to_fetal_brain_seg_dir' "
                "(in bashrc).")
    else:
        try:
            import monaifbs
            DIR_FETAL_BRAIN_SEG = os.path.dirname(monaifbs.__file__)
        except ImportError as e:
            raise RuntimeError(
                "monaifbs not correctly installed. "
                "Please check its installation running "
                "pip install -e MONAIfbs/ "
            )

    print("Using executable from {}".format(DIR_FETAL_BRAIN_SEG))

    if args.filenames_masks is None and args.dir_output is None:
        raise IOError("Either --filenames-masks or --dir-output must be set")

    if args.dir_output is not None:
        args.filenames_masks = [
            os.path.join(args.dir_output, os.path.basename(f))
            for f in args.filenames
        ]

    if len(args.filenames) != len(args.filenames_masks):
        raise IOError("Number of filenames and filenames-masks must match")

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

    cd_fetal_brain_seg = "cd %s" % DIR_FETAL_BRAIN_SEG

    for f, m in zip(args.filenames, args.filenames_masks):

        if not ph.file_exists(f):
            raise IOError("File '%s' does not exist" % f)

        # use absolute path for input image
        f = os.path.abspath(f)

        # use absolute path for output image
        dir_output = os.path.dirname(m)
        if not os.path.isabs(dir_output):
            dir_output = os.path.realpath(
                os.path.join(os.getcwd(), dir_output))
            m = os.path.join(dir_output, os.path.basename(m))

        ph.create_directory(dir_output)

        # Change to root directory of fetal_brain_seg
        cmds = [cd_fetal_brain_seg]

        # Run masking independently (Takes longer but ensures that it does
        # not terminate because of provided 'non-brain images')
        cmd_args = ["python fetal_brain_seg.py"]
        cmd_args.append("--input_names '%s'" % f)
        cmd_args.append("--segment_output_names '%s'" % m)
        cmds.append(" ".join(cmd_args))

        # Execute both steps
        cmd = " && ".join(cmds)
        flag = ph.execute_command(cmd)

        if flag != 0:
            ph.print_warning(
                "Error using fetal_brain_seg. \n"
                "Execute '%s' for further investigation" %
                cmd)

        ph.print_info("Fetal brain segmentation written to '%s'" % m)

        if args.verbose:
            ph.show_nifti(f, segmentation=m)

    elapsed_time_total = ph.stop_timing(time_start)

    ph.print_title("Summary")
    exe_file_info = os.path.basename(os.path.abspath(__file__)).split(".")[0]
    print("%s | Computational Time: %s" % (exe_file_info, elapsed_time_total))

    return 0
Exemplo n.º 25
0
    def run(self):

        print_precisicion = 3
        print_suppress = True

        if self._optimizer_method in ["lm"]:
            verbose = 1
            if self._optimizer_loss not in ["linear"]:
                self._optimizer_loss = "linear"
                print(
                    "Optimizer method 'lm' only supports 'linear' loss function. "
                )

        else:
            verbose = 2

        jac = '2-point'
        # jac = '3-point'
        x_scale = 1.0  # or array
        # x_scale = 'jac' #or array

        # Initialize registration pipeline
        self._run_registration_pipeline_initialization()

        if self._use_verbose:
            print("Initial values = ")
            ph.print_numpy_array(self._parameters,
                                 precision=print_precisicion,
                                 suppress=print_suppress)

        # Parameter normalization
        if self._use_parameter_normalization:
            parameter_normalization = pn.ParameterNormalization(
                self._parameters)
            parameter_normalization.compute_normalization_coefficients()
            coefficients = parameter_normalization.get_normalization_coefficients(
            )

            # Use absolute mean for normalization
            scale = abs(np.array(coefficients[0]))

            # scale could be zero (like for rotation)
            scale[np.where(scale == 0)] = 1

            if self._use_verbose:
                print("Normalization parameters:")
                ph.print_numpy_array(scale,
                                     precision=print_precisicion,
                                     suppress=print_suppress)

            # Each slice with the same scaling
            x_scale = np.tile(scale, self._parameters.shape[0])

        # HACK
        self._transforms_2D_itk = [None] * self._N_slices
        for i in range(0, self._N_slices):
            self._transforms_2D_itk[i] = self._new_transform_itk[
                self._transform_type]()
            self._transforms_2D_itk[i].SetParameters(
                itk.OptimizerParameters[itk.D](
                    self._transforms_2D_sitk[i].GetParameters()))
            self._transforms_2D_itk[i].SetFixedParameters(
                itk.OptimizerParameters[itk.D](
                    self._transforms_2D_sitk[i].GetFixedParameters()))

        # Get cost function and its Jacobian w.r.t. the parameters
        fun = self._get_residual_call()
        jac = self._get_jacobian_residual_call()
        x0 = self._parameters0_vec.flatten()

        time_start = ph.start_timing()

        if self._optimizer == "least_squares":
            self._print_info_text_least_squares()
            res = self._run_optimizer_least_squares(
                fun=fun,
                jac=jac,
                x0=x0,
                method=self._optimizer_method,
                loss=self._optimizer_loss,
                iter_max=self._optimizer_iter_max,
                verbose=verbose,
                x_scale=x_scale)
        else:
            self._print_info_text_minimize()
            res = self._run_optimizer_minimize(
                fun=fun,
                jac=jac,
                x0=x0,
                method=self._optimizer,
                loss=self._optimizer_loss,
                iter_max=self._optimizer_iter_max,
                verbose=verbose,
                x_scale=x_scale)

        self._elapsed_time = ph.stop_timing(time_start)

        # Get and reshape final transform parameters for each slice
        self._parameters = res.reshape(self._parameters.shape)

        # Denormalize parameters
        # self._parameters = self._parameter_normalizer.denormalize_parameters(self._parameters)

        if self._use_verbose:
            print("Final values = ")
            ph.print_numpy_array(self._parameters,
                                 precision=print_precisicion,
                                 suppress=print_suppress)
        # if self._use_verbose:
        #     print("Final values = ")
        #     print(self._parameters)

        # Apply motion correction and compute slice transforms
        self._apply_motion_correction()
Exemplo n.º 26
0
def main():

    time_start = ph.start_timing()

    np.set_printoptions(precision=3)

    input_parser = InputArgparser(
        description="Register an obtained reconstruction (moving) "
        "to a template image/space (fixed) using rigid registration. "
        "The resulting registration can optionally be applied to previously "
        "obtained motion correction slice transforms so that a volumetric "
        "reconstruction is possible in the (standard anatomical) space "
        "defined by the fixed.", )
    input_parser.add_fixed(required=True)
    input_parser.add_moving(required=True)
    input_parser.add_output(help="Path to registration transform (.txt)",
                            required=True)
    input_parser.add_fixed_mask()
    input_parser.add_moving_mask()
    input_parser.add_dir_input_mc()
    input_parser.add_search_angle(default=180)
    input_parser.add_option(option_string="--initial-transform",
                            type=str,
                            help="Path to initial transform.",
                            default=None)
    input_parser.add_option(
        option_string="--test-ap-flip",
        type=int,
        help="Turn on/off functionality to run an additional registration "
        "after an AP-flip. Seems to be more robust to find a better "
        "registration outcome in general.",
        default=1)
    input_parser.add_option(
        option_string="--use-flirt",
        type=int,
        help="Turn on/off functionality to use FLIRT for the registration.",
        default=1)
    input_parser.add_option(
        option_string="--use-regaladin",
        type=int,
        help="Turn on/off functionality to use RegAladin for the "
        "registration.",
        default=1)
    input_parser.add_verbose(default=0)
    input_parser.add_log_config(default=1)

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

    debug = 0

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

    if not args.use_regaladin and not args.use_flirt:
        raise IOError("Either RegAladin or FLIRT must be activated.")

    if not args.output.endswith(".txt"):
        raise IOError("output transformation path must end in '.txt'")

    dir_output = os.path.dirname(args.output)

    # --------------------------------Read Data--------------------------------
    ph.print_title("Read Data")
    fixed = st.Stack.from_filename(file_path=args.fixed,
                                   file_path_mask=args.fixed_mask,
                                   extract_slices=False)
    moving = st.Stack.from_filename(file_path=args.moving,
                                    file_path_mask=args.moving_mask,
                                    extract_slices=False)

    if args.initial_transform is not None:
        transform_sitk = sitkh.read_transform_sitk(args.initial_transform)
    else:
        transform_sitk = sitk.AffineTransform(fixed.sitk.GetDimension())
    sitk.WriteTransform(transform_sitk, args.output)

    path_to_tmp_output = os.path.join(
        DIR_TMP, ph.append_to_filename(os.path.basename(args.moving),
                                       "_warped"))

    # -------------------Register Reconstruction to Template-------------------
    ph.print_title("Register Reconstruction to Template")

    if args.use_flirt:
        path_to_transform_flirt = os.path.join(DIR_TMP, "transform_flirt.txt")

        # Convert SimpleITK into FLIRT transform
        cmd = "simplereg_transform -sitk2flirt %s %s %s %s" % (
            args.output, args.fixed, args.moving, path_to_transform_flirt)
        ph.execute_command(cmd, verbose=False)

        # Define search angle ranges for FLIRT in all three dimensions
        search_angles = [
            "-searchr%s -%d %d" % (x, args.search_angle, args.search_angle)
            for x in ["x", "y", "z"]
        ]

        # flt = nipype.interfaces.fsl.FLIRT()
        # flt.inputs.in_file = args.moving
        # flt.inputs.reference = args.fixed
        # if args.initial_transform is not None:
        #     flt.inputs.in_matrix_file = path_to_transform_flirt
        # flt.inputs.out_matrix_file = path_to_transform_flirt
        # # flt.inputs.output_type = "NIFTI_GZ"
        # flt.inputs.out_file = path_to_tmp_output
        # flt.inputs.args = "-dof 6"
        # flt.inputs.args += " %s" % " ".join(search_angles)
        # if args.moving_mask is not None:
        #     flt.inputs.in_weight = args.moving_mask
        # if args.fixed_mask is not None:
        #     flt.inputs.ref_weight = args.fixed_mask
        # ph.print_info("Run Registration (FLIRT) ... ", newline=False)
        # flt.run()
        # print("done")

        cmd_args = ["flirt"]
        cmd_args.append("-in %s" % args.moving)
        cmd_args.append("-ref %s" % args.fixed)
        if args.initial_transform is not None:
            cmd_args.append("-init %s" % path_to_transform_flirt)
        cmd_args.append("-omat %s" % path_to_transform_flirt)
        cmd_args.append("-out %s" % path_to_tmp_output)
        cmd_args.append("-dof 6")
        cmd_args.append((" ").join(search_angles))
        if args.moving_mask is not None:
            cmd_args.append("-inweight %s" % args.moving_mask)
        if args.fixed_mask is not None:
            cmd_args.append("-refweight %s" % args.fixed_mask)
        ph.print_info("Run Registration (FLIRT) ... ", newline=False)
        ph.execute_command(" ".join(cmd_args), verbose=False)
        print("done")

        # Convert FLIRT to SimpleITK transform
        cmd = "simplereg_transform -flirt2sitk %s %s %s %s" % (
            path_to_transform_flirt, args.fixed, args.moving, args.output)
        ph.execute_command(cmd, verbose=False)

        if debug:
            ph.show_niftis([args.fixed, path_to_tmp_output])

    # Additionally, use RegAladin for more accurate alignment
    # Rationale: FLIRT has better capture range, but RegAladin seems to
    # find better alignment once it is within its capture range.
    if args.use_regaladin:
        path_to_transform_regaladin = os.path.join(DIR_TMP,
                                                   "transform_regaladin.txt")

        # Convert SimpleITK to RegAladin transform
        cmd = "simplereg_transform -sitk2nreg %s %s" % (
            args.output, path_to_transform_regaladin)
        ph.execute_command(cmd, verbose=False)

        # nreg = nipype.interfaces.niftyreg.RegAladin()
        # nreg.inputs.ref_file = args.fixed
        # nreg.inputs.flo_file = args.moving
        # nreg.inputs.res_file = path_to_tmp_output
        # nreg.inputs.in_aff_file = path_to_transform_regaladin
        # nreg.inputs.aff_file = path_to_transform_regaladin
        # nreg.inputs.args = "-rigOnly -voff"
        # if args.moving_mask is not None:
        #     nreg.inputs.fmask_file = args.moving_mask
        # if args.fixed_mask is not None:
        #     nreg.inputs.rmask_file = args.fixed_mask
        # ph.print_info("Run Registration (RegAladin) ... ", newline=False)
        # nreg.run()
        # print("done")

        cmd_args = ["reg_aladin"]
        cmd_args.append("-ref %s" % args.fixed)
        cmd_args.append("-flo %s" % args.moving)
        cmd_args.append("-res %s" % path_to_tmp_output)
        if args.initial_transform is not None or args.use_flirt == 1:
            cmd_args.append("-inaff %s" % path_to_transform_regaladin)
        cmd_args.append("-aff %s" % path_to_transform_regaladin)
        # cmd_args.append("-cog")
        # cmd_args.append("-ln 2")
        cmd_args.append("-rigOnly")
        cmd_args.append("-voff")
        if args.moving_mask is not None:
            cmd_args.append("-fmask %s" % args.moving_mask)
        if args.fixed_mask is not None:
            cmd_args.append("-rmask %s" % args.fixed_mask)
        ph.print_info("Run Registration (RegAladin) ... ", newline=False)
        ph.execute_command(" ".join(cmd_args), verbose=False)
        print("done")

        # Convert RegAladin to SimpleITK transform
        cmd = "simplereg_transform -nreg2sitk %s %s" % (
            path_to_transform_regaladin, args.output)
        ph.execute_command(cmd, verbose=False)

        if debug:
            ph.show_niftis([args.fixed, path_to_tmp_output])

    if args.test_ap_flip:
        path_to_transform_flip = os.path.join(DIR_TMP, "transform_flip.txt")
        path_to_tmp_output_flip = os.path.join(DIR_TMP, "output_flip.nii.gz")

        # Get AP-flip transform
        transform_ap_flip_sitk = get_ap_flip_transform(args.fixed)
        path_to_transform_flip_regaladin = os.path.join(
            DIR_TMP, "transform_flip_regaladin.txt")
        sitk.WriteTransform(transform_ap_flip_sitk, path_to_transform_flip)

        # Compose current transform with AP flip transform
        cmd = "simplereg_transform -c %s %s %s" % (
            args.output, path_to_transform_flip, path_to_transform_flip)
        ph.execute_command(cmd, verbose=False)

        # Convert SimpleITK to RegAladin transform
        cmd = "simplereg_transform -sitk2nreg %s %s" % (
            path_to_transform_flip, path_to_transform_flip_regaladin)
        ph.execute_command(cmd, verbose=False)

        # nreg = nipype.interfaces.niftyreg.RegAladin()
        # nreg.inputs.ref_file = args.fixed
        # nreg.inputs.flo_file = args.moving
        # nreg.inputs.res_file = path_to_tmp_output_flip
        # nreg.inputs.in_aff_file = path_to_transform_flip_regaladin
        # nreg.inputs.aff_file = path_to_transform_flip_regaladin
        # nreg.inputs.args = "-rigOnly -voff"
        # if args.moving_mask is not None:
        #     nreg.inputs.fmask_file = args.moving_mask
        # if args.fixed_mask is not None:
        #     nreg.inputs.rmask_file = args.fixed_mask
        # ph.print_info("Run Registration AP-flipped (RegAladin) ... ",
        #               newline=False)
        # nreg.run()
        # print("done")

        cmd_args = ["reg_aladin"]
        cmd_args.append("-ref %s" % args.fixed)
        cmd_args.append("-flo %s" % args.moving)
        cmd_args.append("-res %s" % path_to_tmp_output_flip)
        cmd_args.append("-inaff %s" % path_to_transform_flip_regaladin)
        cmd_args.append("-aff %s" % path_to_transform_flip_regaladin)
        cmd_args.append("-rigOnly")
        # cmd_args.append("-ln 2")
        cmd_args.append("-voff")
        if args.moving_mask is not None:
            cmd_args.append("-fmask %s" % args.moving_mask)
        if args.fixed_mask is not None:
            cmd_args.append("-rmask %s" % args.fixed_mask)
        ph.print_info("Run Registration AP-flipped (RegAladin) ... ",
                      newline=False)
        ph.execute_command(" ".join(cmd_args), verbose=False)
        print("done")

        if debug:
            ph.show_niftis(
                [args.fixed, path_to_tmp_output, path_to_tmp_output_flip])

        warped_moving = st.Stack.from_filename(path_to_tmp_output,
                                               extract_slices=False)
        warped_moving_flip = st.Stack.from_filename(path_to_tmp_output_flip,
                                                    extract_slices=False)
        fixed = st.Stack.from_filename(args.fixed, args.fixed_mask)

        stacks = [warped_moving, warped_moving_flip]
        image_similarity_evaluator = ise.ImageSimilarityEvaluator(
            stacks=stacks, reference=fixed)
        image_similarity_evaluator.compute_similarities()
        similarities = image_similarity_evaluator.get_similarities()

        if similarities["NMI"][1] > similarities["NMI"][0]:
            ph.print_info("AP-flipped outcome better")

            # Convert RegAladin to SimpleITK transform
            cmd = "simplereg_transform -nreg2sitk %s %s" % (
                path_to_transform_flip_regaladin, args.output)
            ph.execute_command(cmd, verbose=False)

            # Copy better outcome
            cmd = "cp -p %s %s" % (path_to_tmp_output_flip, path_to_tmp_output)
            ph.execute_command(cmd, verbose=False)

        else:
            ph.print_info("AP-flip does not improve outcome")

    if args.dir_input_mc is not None:
        transform_sitk = sitkh.read_transform_sitk(args.output, inverse=1)

        if args.dir_input_mc.endswith("/"):
            subdir_mc = args.dir_input_mc.split("/")[-2]
        else:
            subdir_mc = args.dir_input_mc.split("/")[-1]
        dir_output_mc = os.path.join(dir_output, subdir_mc)

        ph.create_directory(dir_output_mc, delete_files=True)
        pattern = REGEX_FILENAMES + "[.]tfm"
        p = re.compile(pattern)
        trafos = [t for t in os.listdir(args.dir_input_mc) if p.match(t)]
        for t in trafos:
            path_to_input_transform = os.path.join(args.dir_input_mc, t)
            path_to_output_transform = os.path.join(dir_output_mc, t)
            t_sitk = sitkh.read_transform_sitk(path_to_input_transform)
            t_sitk = sitkh.get_composite_sitk_affine_transform(
                transform_sitk, t_sitk)
            sitk.WriteTransform(t_sitk, path_to_output_transform)

    if args.verbose:
        ph.show_niftis([args.fixed, path_to_tmp_output])

    elapsed_time_total = ph.stop_timing(time_start)

    # Summary
    ph.print_title("Summary")
    print("Computational Time: %s" % (elapsed_time_total))

    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="Perform automatic brain masking using "
        "fetal_brain_seg (https://github.com/gift-surg/fetal_brain_seg). ", )
    input_parser.add_filenames(required=True)
    input_parser.add_filenames_masks(required=False)
    input_parser.add_dir_output(required=False)
    input_parser.add_verbose(default=0)
    input_parser.add_log_config(default=0)

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

    try:
        DIR_FETAL_BRAIN_SEG = os.environ["FETAL_BRAIN_SEG"]
    except KeyError as e:
        raise RuntimeError(
            "Environment variable FETAL_BRAIN_SEG is not specified. "
            "Specify the root directory of fetal_brain_seg "
            "(https://github.com/gift-surg/fetal_brain_seg) "
            "using "
            "'export FETAL_BRAIN_SEG=path_to_fetal_brain_seg_dir' "
            "(in bashrc).")

    if args.filenames_masks is None and args.dir_output is None:
        raise IOError("Either --filenames-masks or --dir-output must be set")

    if args.dir_output is not None:
        args.filenames_masks = [
            os.path.join(args.dir_output, os.path.basename(f))
            for f in args.filenames
        ]

    if len(args.filenames) != len(args.filenames_masks):
        raise IOError("Number of filenames and filenames-masks must match")

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

    cd_fetal_brain_seg = "cd %s" % DIR_FETAL_BRAIN_SEG

    for f, m in zip(args.filenames, args.filenames_masks):

        if not ph.file_exists(f):
            raise IOError("File '%s' does not exist" % f)

        # use absolute path for input image
        f = os.path.abspath(f)

        # use absolute path for output image
        dir_output = os.path.dirname(m)
        if not os.path.isabs(dir_output):
            dir_output = os.path.realpath(os.path.join(os.getcwd(),
                                                       dir_output))
            m = os.path.join(dir_output, os.path.basename(m))

        ph.create_directory(dir_output)

        # Change to root directory of fetal_brain_seg
        cmds = [cd_fetal_brain_seg]

        # Run masking independently (Takes longer but ensures that it does
        # not terminate because of provided 'non-brain images')
        cmd_args = ["python fetal_brain_seg.py"]
        cmd_args.append("--input_names '%s'" % f)
        cmd_args.append("--segment_output_names '%s'" % m)
        cmds.append(" ".join(cmd_args))

        # Execute both steps
        cmd = " && ".join(cmds)
        flag = ph.execute_command(cmd)

        if flag != 0:
            ph.print_warning("Error using fetal_brain_seg. \n"
                             "Execute '%s' for further investigation" % cmd)

        ph.print_info("Fetal brain segmentation written to '%s'" % m)

        if args.verbose:
            ph.show_nifti(f, segmentation=m)

    return 0
def main():

    time_start = ph.start_timing()

    # Set print options for numpy
    np.set_printoptions(precision=3)

    # Read input
    input_parser = InputArgparser(
        description="Script to study reconstruction parameters and their "
        "impact on the volumetric reconstruction quality. "
        "This script can only be used to sweep through one single parameter, "
        "e.g. the regularization parameter 'alpha'. ")
    input_parser.add_filenames(required=True)
    input_parser.add_filenames_masks()
    input_parser.add_suffix_mask(default="_mask")
    input_parser.add_dir_input_mc()
    input_parser.add_dir_output(required=True)
    input_parser.add_reconstruction_space()
    input_parser.add_reference(
        help="Path to reference NIfTI image file. If given the volumetric "
        "reconstructed is performed in this physical space. "
        "Either a reconstruction space or a reference must be provided",
        required=False)
    input_parser.add_reference_mask(default=None)
    input_parser.add_study_name()
    input_parser.add_reconstruction_type(default="TK1L2")
    input_parser.add_measures(
        default=["PSNR", "MAE", "RMSE", "SSIM", "NCC", "NMI"])
    input_parser.add_tv_solver(default="PD")
    input_parser.add_iterations(default=50)
    input_parser.add_rho(default=0.1)
    input_parser.add_iter_max(default=10)
    input_parser.add_minimizer(default="lsmr")
    input_parser.add_log_config(default=1)
    input_parser.add_use_masks_srr(default=0)
    input_parser.add_verbose(default=1)
    input_parser.add_slice_thicknesses(default=None)
    input_parser.add_argument(
        "--append",
        "-append",
        action='store_true',
        help="If given, results are appended to previously executed parameter "
        "study with identical parameters and study name store in the output "
        "directory.")

    # Range for parameter sweeps
    input_parser.add_alphas(default=list(np.linspace(0.01, 0.5, 5)))
    input_parser.add_data_losses(default=["linear"]
                                 # default=["linear", "arctan"]
                                 )
    input_parser.add_data_loss_scales(default=[1]
                                      # default=[0.1, 0.5, 1.5]
                                      )

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

    if args.reference is None and args.reconstruction_space is None:
        raise IOError("Either reference (--reference) or reconstruction space "
                      "(--reconstruction-space) must be provided.")

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

    # --------------------------------Read Data--------------------------------
    ph.print_title("Read Data")

    data_reader = dr.MultipleImagesReader(
        file_paths=args.filenames,
        file_paths_masks=args.filenames_masks,
        suffix_mask=args.suffix_mask,
        dir_motion_correction=args.dir_input_mc,
        stacks_slice_thicknesses=args.slice_thicknesses,
    )

    data_reader.read_data()
    stacks = data_reader.get_data()
    ph.print_info("%d input stacks read for further processing" % len(stacks))

    if args.reference is not None:
        reference = st.Stack.from_filename(file_path=args.reference,
                                           file_path_mask=args.reference_mask,
                                           extract_slices=False)

        reconstruction_space = stacks[0].get_resampled_stack(reference.sitk)
        reconstruction_space = \
            reconstruction_space.get_stack_multiplied_with_mask()
        x_ref = sitk.GetArrayFromImage(reference.sitk).flatten()
        x_ref_mask = sitk.GetArrayFromImage(reference.sitk_mask).flatten()

    else:
        reconstruction_space = st.Stack.from_filename(
            file_path=args.reconstruction_space, extract_slices=False)
        reconstruction_space = stacks[0].get_resampled_stack(
            reconstruction_space.sitk)
        reconstruction_space = \
            reconstruction_space.get_stack_multiplied_with_mask()
        x_ref = None
        x_ref_mask = None

    # ----------------------------Set Up Parameters----------------------------
    parameters = {}
    parameters["alpha"] = args.alphas
    if len(args.data_losses) > 1:
        parameters["data_loss"] = args.data_losses
    if len(args.data_loss_scales) > 1:
        parameters["data_loss_scale"] = args.data_loss_scales

    # --------------------------Set Up Parameter Study-------------------------
    ph.print_title("Run Parameter Study")
    if args.study_name is None:
        name = args.reconstruction_type
    else:
        name = args.study_name

    reconstruction_info = {
        "shape": reconstruction_space.sitk.GetSize()[::-1],
        "origin": reconstruction_space.sitk.GetOrigin(),
        "spacing": reconstruction_space.sitk.GetSpacing(),
        "direction": reconstruction_space.sitk.GetDirection(),
    }

    # Create Tikhonov solver from which all information can be extracted
    # (also for other reconstruction types)
    tmp = tk.TikhonovSolver(
        stacks=stacks,
        reconstruction=reconstruction_space,
        alpha=args.alphas[0],
        iter_max=args.iter_max,
        data_loss=args.data_losses[0],
        data_loss_scale=args.data_loss_scales[0],
        reg_type="TK1",
        minimizer=args.minimizer,
        verbose=args.verbose,
        use_masks=args.use_masks_srr,
    )
    solver = tmp.get_solver()

    parameter_study_interface = \
        deconv_interface.DeconvolutionParameterStudyInterface(
            A=solver.get_A(),
            A_adj=solver.get_A_adj(),
            D=solver.get_B(),
            D_adj=solver.get_B_adj(),
            b=solver.get_b(),
            x0=solver.get_x0(),
            alpha=solver.get_alpha(),
            x_scale=solver.get_x_scale(),
            data_loss=solver.get_data_loss(),
            data_loss_scale=solver.get_data_loss_scale(),
            iter_max=solver.get_iter_max(),
            minimizer=solver.get_minimizer(),
            iterations=args.iterations,
            measures=args.measures,
            dimension=3,
            L2=16. / reconstruction_space.sitk.GetSpacing()[0]**2,
            reconstruction_type=args.reconstruction_type,
            rho=args.rho,
            dir_output=args.dir_output,
            parameters=parameters,
            name=name,
            reconstruction_info=reconstruction_info,
            x_ref=x_ref,
            x_ref_mask=x_ref_mask,
            tv_solver=args.tv_solver,
            verbose=args.verbose,
            append=args.append,
        )
    parameter_study_interface.set_up_parameter_study()
    parameter_study = parameter_study_interface.get_parameter_study()

    # Run parameter study
    parameter_study.run()

    print("\nComputational time for Deconvolution Parameter Study %s: %s" %
          (name, parameter_study.get_computational_time()))

    return 0
Exemplo n.º 30
0
def main():

    time_start = ph.start_timing()

    # Set print options for numpy
    np.set_printoptions(precision=3)

    input_parser = InputArgparser(
        description="Propagate image mask using rigid registration.", )
    input_parser.add_moving(required=True)
    input_parser.add_moving_mask(required=True)
    input_parser.add_fixed(required=True)
    input_parser.add_output(required=True)
    input_parser.add_v2v_method(
        option_string="--method",
        help="Registration method used for the registration (%s)." %
        (", or ".join(V2V_METHOD_OPTIONS)),
        default="RegAladin",
    )
    input_parser.add_option(
        option_string="--use-moving-mask",
        type=int,
        help="Turn on/off use of moving mask to constrain the registration.",
        default=0,
    )
    input_parser.add_dilation_radius(default=1)
    input_parser.add_verbose(default=0)
    input_parser.add_log_config(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.method not in V2V_METHOD_OPTIONS:
        raise ValueError("method must be in {%s}" %
                         (", ".join(V2V_METHOD_OPTIONS)))

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

    stack = st.Stack.from_filename(
        file_path=args.fixed,
        extract_slices=False,
    )
    template = st.Stack.from_filename(
        file_path=args.moving,
        file_path_mask=args.moving_mask,
        extract_slices=False,
    )

    if args.method == "FLIRT":
        # Define search angle ranges for FLIRT in all three dimensions
        # search_angles = ["-searchr%s -%d %d" %
        #                  (x, args.search_angle, args.search_angle)
        #                  for x in ["x", "y", "z"]]
        # options = (" ").join(search_angles)
        # options += " -noresample"

        registration = regflirt.FLIRT(
            registration_type="Rigid",
            fixed=stack,
            moving=template,
            use_fixed_mask=False,
            use_moving_mask=args.use_moving_mask,
            # options=options,
            use_verbose=False,
        )
    else:
        registration = niftyreg.RegAladin(
            registration_type="Rigid",
            fixed=stack,
            moving=template,
            use_fixed_mask=False,
            use_moving_mask=args.use_moving_mask,
            # options="-ln 2",
            use_verbose=False,
        )

    try:
        registration.run()
    except RuntimeError as e:
        raise RuntimeError(
            "%s\n\n"
            "Have you tried running the script with '--use-moving-mask 0'?" %
            e)

    transform_sitk = registration.get_registration_transform_sitk()
    stack.sitk_mask = sitk.Resample(template.sitk_mask, stack.sitk_mask,
                                    transform_sitk, sitk.sitkNearestNeighbor,
                                    0, template.sitk_mask.GetPixelIDValue())
    if args.dilation_radius > 0:
        stack_mask_morpher = stmorph.StackMaskMorphologicalOperations.from_sitk_mask(
            mask_sitk=stack.sitk_mask,
            dilation_radius=args.dilation_radius,
            dilation_kernel="Ball",
            use_dilation_in_plane_only=True,
        )
        stack_mask_morpher.run_dilation()
        stack.sitk_mask = stack_mask_morpher.get_processed_mask_sitk()

    dw.DataWriter.write_mask(stack.sitk_mask, args.output)

    elapsed_time = ph.stop_timing(time_start)

    if args.verbose:
        ph.show_nifti(args.fixed, segmentation=args.output)

    ph.print_title("Summary")
    exe_file_info = os.path.basename(os.path.abspath(__file__)).split(".")[0]
    print("%s | Computational Time for Segmentation Propagation: %s" %
          (exe_file_info, elapsed_time))

    return 0