Beispiel #1
0
    def _parse_config_file(self):

        # Read path to config file
        path_to_config_file = sys.argv[sys.argv.index(self._config_arg) + 1]

        # Read config file and insert all config entries into sys.argv (read by
        # argparse later)
        dic = ph.read_dictionary_from_json(path_to_config_file)

        # Insert all config entries into sys.argv
        for k, v in six.iteritems(dic):

            if k == "version":
                continue

            # A 'None' entry should be ignored
            if v is None:
                continue

            # Insert values as string right at the beginning of arguments
            # Rationale: Later options, outside of the config file, will
            # overwrite the config values
            if type(v) is list:
                for vi in reversed(v):
                    sys.argv.insert(1, str(vi))
            # 'store_true' values are converted to True/False; ignore the value
            # of this key as the existence of the key indicates 'True'
            elif type(v) is bool:
                if v == True:
                    sys.argv.insert(1, "--%s" % k)
                continue
            else:
                sys.argv.insert(1, str(v))

            sys.argv.insert(1, "--%s" % k)
Beispiel #2
0
    def run(self):
        if not ph.directory_exists(self._dir_motion_correction):
            raise exceptions.DirectoryNotExistent(self._dir_motion_correction)
        abs_path_to_directory = os.path.abspath(self._dir_motion_correction)

        path_to_rejected_slices = os.path.join(abs_path_to_directory,
                                               "rejected_slices.json")
        if ph.file_exists(path_to_rejected_slices):
            self._rejected_slices = ph.read_dictionary_from_json(
                path_to_rejected_slices)
            bool_check = True
        else:
            self._rejected_slices = None
            bool_check = False

        for i in range(len(self._stacks)):
            stack_name = self._stacks[i].get_filename()

            # update stack position
            path_to_stack_transform = os.path.join(abs_path_to_directory,
                                                   "%s.tfm" % stack_name)
            if ph.file_exists(path_to_stack_transform):
                transform_stack_sitk = sitkh.read_transform_sitk(
                    path_to_stack_transform)
                transform_stack_sitk_inv = sitkh.read_transform_sitk(
                    path_to_stack_transform, inverse=True)
                self._stacks[i].update_motion_correction(transform_stack_sitk)
                ph.print_info("Stack '%s': Stack position updated" %
                              stack_name)
            else:
                transform_stack_sitk_inv = sitk.Euler3DTransform()

            # update slice positions
            pattern_trafo_slices = stack_name + self._prefix_slice + \
                "([0-9]+)[.]tfm"
            p = re.compile(pattern_trafo_slices)
            dic_slice_transforms = {
                int(p.match(f).group(1)): os.path.join(abs_path_to_directory,
                                                       p.match(f).group(0))
                for f in os.listdir(abs_path_to_directory) if p.match(f)
            }
            slices = self._stacks[i].get_slices()
            for i_slice in range(self._stacks[i].get_number_of_slices()):
                if i_slice in dic_slice_transforms.keys() and \
                        self._check_against_json[bool_check](
                            stack_name, i_slice):
                    transform_slice_sitk = sitkh.read_transform_sitk(
                        dic_slice_transforms[i_slice])
                    transform_slice_sitk = \
                        sitkh.get_composite_sitk_affine_transform(
                            transform_slice_sitk, transform_stack_sitk_inv)
                    slices[i_slice].update_motion_correction(
                        transform_slice_sitk)

                    # # ------------------------- HACK ------------------------
                    # # 18 Jan 2019
                    # # HACK to use results of a previous version where image
                    # # slices were still exported
                    # # (Bug was that after stack intensity correction, the
                    # # previous v2v-reg was not passed on to the final
                    # # registration transform):
                    # import niftymic.base.slice as sl
                    # path_to_slice = re.sub(
                    #     ".tfm", ".nii.gz", dic_slice_transforms[i_slice])
                    # path_to_slice_mask = re.sub(
                    #     ".tfm", "_mask.nii.gz", dic_slice_transforms[i_slice])
                    # slice_sitk = sitk.ReadImage(path_to_slice)
                    # slice_sitk_mask = sitk.ReadImage(path_to_slice_mask)
                    # hack = sl.Slice.from_sitk_image(
                    #     # slice_sitk=slice_sitk,
                    #     slice_sitk=slice_sitk_mask,  # mask for Mask-SRR!
                    #     slice_sitk_mask=slice_sitk_mask,
                    #     slice_number=slices[i_slice].get_slice_number(),
                    #     slice_thickness=slices[i_slice].get_slice_thickness(),
                    # )
                    # self._stacks[i]._slices[i_slice] = hack
                    # # -------------------------------------------------------

                else:
                    self._stacks[i].delete_slice(slices[i_slice])

            # print update information
            ph.print_info("Stack '%s': Slice positions updated "
                          "(%d/%d slices deleted)" % (
                              stack_name,
                              len(self._stacks[i].get_deleted_slice_numbers()),
                              self._stacks[i].sitk.GetSize()[-1],
                          ))

            # delete entire stack if all slices were rejected
            if self._stacks[i].get_number_of_slices() == 0:
                ph.print_info("Stack '%s' removed as all slices were deleted" %
                              stack_name)
                self._stacks[i] = None

        # only return maintained stacks
        self._stacks = [s for s in self._stacks if s is not None]

        if len(self._stacks) == 0:
            raise RuntimeError(
                "All stacks removed. "
                "Did you check that the correct motion-correction directory "
                "was provided?")
    def run(self, older_than_v3=False):
        if not ph.directory_exists(self._dir_motion_correction):
            raise exceptions.DirectoryNotExistent(
                self._dir_motion_correction)
        abs_path_to_directory = os.path.abspath(
            self._dir_motion_correction)

        path_to_rejected_slices = os.path.join(
            abs_path_to_directory, "rejected_slices.json")
        if ph.file_exists(path_to_rejected_slices):
            self._rejected_slices = ph.read_dictionary_from_json(
                path_to_rejected_slices)
            bool_check = True
        else:
            self._rejected_slices = None
            bool_check = False

        for i in range(len(self._stacks)):
            stack_name = self._stacks[i].get_filename()

            if not older_than_v3:
                # update stack position
                path_to_stack_transform = os.path.join(
                    abs_path_to_directory, "%s.tfm" % stack_name)
                if ph.file_exists(path_to_stack_transform):
                    transform_stack_sitk = sitkh.read_transform_sitk(
                        path_to_stack_transform)
                    transform_stack_sitk_inv = sitkh.read_transform_sitk(
                        path_to_stack_transform, inverse=True)
                    self._stacks[i].update_motion_correction(
                        transform_stack_sitk)
                    ph.print_info(
                        "Stack '%s': Stack position updated" % stack_name)
                else:
                    transform_stack_sitk_inv = sitk.Euler3DTransform()

                if self._volume_motion_only:
                    continue

                # update slice positions
                pattern_trafo_slices = stack_name + self._prefix_slice + \
                    "([0-9]+)[.]tfm"
                p = re.compile(pattern_trafo_slices)
                dic_slice_transforms = {
                    int(p.match(f).group(1)): os.path.join(
                        abs_path_to_directory, p.match(f).group(0))
                    for f in os.listdir(abs_path_to_directory) if p.match(f)
                }
                slices = self._stacks[i].get_slices()
                for i_slice in range(self._stacks[i].get_number_of_slices()):
                    if i_slice in dic_slice_transforms.keys():
                        transform_slice_sitk = sitkh.read_transform_sitk(
                            dic_slice_transforms[i_slice])
                        transform_slice_sitk = \
                            sitkh.get_composite_sitk_affine_transform(
                                transform_slice_sitk, transform_stack_sitk_inv)
                        slices[i_slice].update_motion_correction(
                            transform_slice_sitk)

                    else:
                        self._stacks[i].delete_slice(slices[i_slice])

            # ----------------------------- HACK -----------------------------
            # 18 Jan 2019
            # HACK to use results of a previous version where image slices were
            # still exported.
            # (There was a bug after stack intensity correction, which resulted
            # in v2v-reg transforms not being part of in the final registration
            # transforms; Thus, slice transformations (tfm's) were flawed and
            # could not be used):
            else:
                # Recover suffix for mask
                pattern = stack_name + self._prefix_slice + \
                    "[0-9]+[_]([a-zA-Z]+)[.]nii.gz"
                pm = re.compile(pattern)
                matches = list(set([pm.match(f).group(1) for f in os.listdir(
                    abs_path_to_directory) if pm.match(f)]))
                if len(matches) > 1:
                    raise RuntimeError("Suffix mask cannot be determined")
                suffix_mask = "_%s" % matches[0]

                # Recover stack
                path_to_stack = os.path.join(
                    abs_path_to_directory, "%s.nii.gz" % stack_name)
                path_to_stack_mask = os.path.join(
                    abs_path_to_directory, "%s%s.nii.gz" % (
                        stack_name, suffix_mask))
                stack = st.Stack.from_filename(
                    path_to_stack, path_to_stack_mask)

                # Recover slices
                pattern_trafo_slices = stack_name + self._prefix_slice + \
                    "([0-9]+)[.]tfm"
                p = re.compile(pattern_trafo_slices)
                dic_slice_transforms = {
                    int(p.match(f).group(1)): os.path.join(
                        abs_path_to_directory, p.match(f).group(0))
                    for f in os.listdir(abs_path_to_directory) if p.match(f)
                }
                slices = self._stacks[i].get_slices()
                for i_slice in range(self._stacks[i].get_number_of_slices()):
                    if i_slice in dic_slice_transforms.keys():
                        path_to_slice = re.sub(
                            ".tfm", ".nii.gz", dic_slice_transforms[i_slice])
                        path_to_slice_mask = re.sub(
                            ".tfm", "%s.nii.gz" % suffix_mask,
                            dic_slice_transforms[i_slice])
                        slice_sitk = sitk.ReadImage(path_to_slice)
                        slice_sitk_mask = sitk.ReadImage(path_to_slice_mask)
                        hack = sl.Slice.from_sitk_image(
                            slice_sitk=slice_sitk,
                            # slice_sitk=slice_sitk_mask,  # mask for Mask-SRR!
                            slice_sitk_mask=slice_sitk_mask,
                            slice_number=slices[i_slice].get_slice_number(),
                            slice_thickness=slices[
                                i_slice].get_slice_thickness(),
                        )
                        self._stacks[i]._slices[i_slice] = hack
                    else:
                        self._stacks[i].delete_slice(slices[i_slice])

                self._stacks[i].sitk = stack.sitk
                self._stacks[i].sitk_mask = stack.sitk_mask
                self._stacks[i].itk = stack.itk
                self._stacks[i].itk_mask = stack.itk_mask
            # -----------------------------------------------------------------

            # print update information
            ph.print_info(
                "Stack '%s': Slice positions updated "
                "(%d/%d slices deleted)" % (
                    stack_name,
                    len(self._stacks[i].get_deleted_slice_numbers()),
                    self._stacks[i].sitk.GetSize()[-1],
                )
            )

            # delete entire stack if all slices were rejected
            if self._stacks[i].get_number_of_slices() == 0:
                ph.print_info(
                    "Stack '%s' removed as all slices were deleted" %
                    stack_name)
                self._stacks[i] = None

        # only return maintained stacks
        self._stacks = [s for s in self._stacks if s is not None]

        if len(self._stacks) == 0:
            raise RuntimeError(
                "All stacks removed. "
                "Did you check that the correct motion-correction directory "
                "was provided?")
Beispiel #4
0
    def test_register_image(self):
        filename = "registration_transform_sitk.txt"
        gestational_age = 28

        path_to_recon = os.path.join(
            self.dir_data, "register_image",
            "SRR_stacks3_TK1_lsmr_alpha0p02_itermax5.nii.gz")
        dir_input_mc = os.path.join(self.dir_data, "register_image",
                                    "motion_correction")

        path_to_transform_res = os.path.join(self.dir_output, filename)
        path_to_transform_ref = os.path.join(self.dir_data, "register_image",
                                             filename)
        dir_ref_mc = os.path.join(self.dir_data, "register_image",
                                  "motion_correction_ref")
        path_to_rejected_slices_ref = os.path.join(dir_ref_mc,
                                                   "rejected_slices.json")

        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 = ["niftymic_register_image"]
        cmd_args.append("--fixed %s" % template)
        cmd_args.append("--moving %s" % path_to_recon)
        cmd_args.append("--fixed-mask %s" % template_mask)
        cmd_args.append("--moving-mask %s" %
                        ph.append_to_filename(path_to_recon, self.suffix_mask))
        cmd_args.append("--dir-input-mc %s" % dir_input_mc)
        cmd_args.append("--output %s" % path_to_transform_res)
        cmd_args.append("--init-pca")
        # cmd_args.append("--verbose 1")
        self.assertEqual(ph.execute_command(" ".join(cmd_args)), 0)

        # Check registration transform
        res_sitk = sitkh.read_transform_sitk(path_to_transform_res)
        ref_sitk = sitkh.read_transform_sitk(path_to_transform_ref)

        res_nda = res_sitk.GetParameters()
        ref_nda = ref_sitk.GetParameters()
        diff_nda = np.array(res_nda) - ref_nda

        self.assertAlmostEqual(np.linalg.norm(diff_nda),
                               0,
                               places=self.precision)

        # Check individual slice transforms
        pattern = REGEX_FILENAMES + "[.]tfm"
        p = re.compile(pattern)
        dir_res_mc = os.path.join(self.dir_output, "motion_correction")
        trafos_res = sorted([
            os.path.join(dir_res_mc, t) for t in os.listdir(dir_res_mc)
            if p.match(t)
        ])
        trafos_ref = sorted([
            os.path.join(dir_ref_mc, t) for t in os.listdir(dir_res_mc)
            if p.match(t)
        ])
        self.assertEqual(len(trafos_res), len(trafos_ref))
        for i in range(len(trafos_ref)):
            nda_res = sitkh.read_transform_sitk(trafos_res[i]).GetParameters()
            nda_ref = sitkh.read_transform_sitk(trafos_ref[i]).GetParameters()
            nda_diff = np.linalg.norm(np.array(nda_res) - nda_ref)
            self.assertAlmostEqual(nda_diff, 0, places=self.precision)

        # Check rejected_slices.json
        path_to_rejected_slices_res = os.path.join(dir_res_mc,
                                                   "rejected_slices.json")
        self.assertEqual(ph.file_exists(path_to_rejected_slices_res), True)
        rejected_slices_res = ph.read_dictionary_from_json(
            path_to_rejected_slices_res)
        rejected_slices_ref = ph.read_dictionary_from_json(
            path_to_rejected_slices_ref)
        self.assertEqual(rejected_slices_res == rejected_slices_ref, True)