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)
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?")
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)