def initialize_registration(self, landmark_path: Path, output_dir: Path): """Use landmark to initialise the registration""" if not output_dir.joinpath("landmarks.dof.gz").exists() or self.overwrite: mirtk.register( str(landmark_path), str(self.template.landmark), model="Rigid", dofout=str(output_dir.joinpath("landmarks.dof.gz")), ) return output_dir.joinpath("landmarks.dof.gz")
def nonrigid_registration(self, mesh: PhaseMesh, lv_label_transformed: Path, rv_label_transformed: Path, lv_affine_transform: Path, rv_affine_transform: Path, fr: Phase, output_dir: Path): temp_dir = output_dir.joinpath("temp") temp_dir.mkdir(exist_ok=True, parents=True) rv_transform = temp_dir.joinpath("rv_{}_nreg.dof.gz".format(fr)) lv_transform = temp_dir.joinpath("lv_{}_nreg.dof.gz".format(fr)) # if not rv_transform.exists() or self.overwrite: # mirtk.register( # str(self.template.vtk_rv(fr)), # str(rv_label_transformed), # model="FFD", # dofin=str(rv_affine_transform), # dofout=str(rv_transform), # parin=str(self.segreg_path), # ) if not rv_transform.exists() or self.overwrite: mirtk.register( str(self.template.rv(fr)), str(mesh.rv.rv), # "-symmetric", "-par", "Point set distance correspondence", "CP", ds=8, model="FFD", dofin=str(rv_affine_transform), dofout=str(rv_transform), ) # if not lv_transform.exists() or self.overwrite: # mirtk.register( # str(self.template.vtk_lv(fr)), # str(lv_label_transformed), # model="FFD", # dofin=str(lv_affine_transform), # dofout=str(lv_transform), # parin=str(self.segreg_path), # ) if not lv_transform.exists() or self.overwrite: mirtk.register( str(self.template.lv_endo(fr)), str(mesh.lv.endocardium), str(self.template.lv_epi(fr)), str(mesh.lv.epicardium), # "-symmetric", "-par", "Energy function", "PCD(T o P(1:2:end), P(2:2:end))", model="FFD", dofin=str(lv_affine_transform), dofout=str(lv_transform), ds=4, ) return lv_transform, rv_transform
def affine_registration(self, lv_label_transformed: Path, rv_label_transformed: Path, fr: Phase, output_dir: Path, mesh): temp_dir = output_dir.joinpath("temp") temp_dir.mkdir(exist_ok=True, parents=True) if not temp_dir.joinpath("smoothed_template_vtk_RV_{}.nii.gz".format(fr)).exists() or self.overwrite: mirtk.smooth_image( str(self.template.vtk_rv(fr)), str(temp_dir.joinpath("smoothed_template_vtk_RV_{}.nii.gz".format(fr))), 1, "-float" ) if not temp_dir.joinpath("rv_{}_areg.dof.gz".format(fr)).exists() or self.overwrite: mirtk.register( str(self.template.rv(fr)), str(mesh.rv.rv), "-par", "Point set distance correspondence", "CP", model="Affine", dofout=str(temp_dir.joinpath("rv_{}_areg.dof.gz".format(fr))), parin=str(self.segareg_path), ) # mirtk.register( # str(temp_dir.joinpath("smoothed_template_vtk_RV_{}.nii.gz".format(fr))), # str(rv_label_transformed), # model="Affine", # dofout=str(temp_dir.joinpath("rv_{}_areg.dof.gz".format(fr))), # parin=str(self.segareg_path), # ) if not temp_dir.joinpath("lv_{}_areg.dof.gz".format(fr)).exists() or self.overwrite: mirtk.register( str(self.template.lv_epi(fr)), str(mesh.lv.epicardium), "-par", "Point set distance correspondence", "CP", model="Affine", dofout=str(temp_dir.joinpath("lv_{}_areg.dof.gz".format(fr))), parin=str(self.segareg_path), ) # mirtk.register( # str(self.template.vtk_lv(fr)), # str(lv_label_transformed), # model="Affine", # dofout=str(temp_dir.joinpath("lv_{}_areg.dof.gz".format(fr))), # parin=str(self.segareg_path), # ) return temp_dir.joinpath("lv_{}_areg.dof.gz".format(fr)), temp_dir.joinpath("rv_{}_areg.dof.gz".format(fr))
def select_altases(self, subject_seg: Path, subject_landmarks: Path, output_dir: Path, n_top: int, force: bool): """Select top similar atlases, according to subject segmentation and landmark""" nmi = [] top_similar_atlases = [] n_atlases = len(self.atlases) # if force: # for f in output_dir.glob("shapenmi*.txt"): # f.unlink() output_dofs = [] top_atlas_dofs = [] for i in range(n_atlases): try: if not output_dir.joinpath( f"shapelandmarks_{i}.dof.gz").exists() or force: mirtk.register( str(subject_landmarks), str(self.landmarks[i]), model="Affine", dofout=str( output_dir.joinpath(f"shapelandmarks_{i}.dof.gz")), ) if not output_dir.joinpath( f"shapenmi_{i}.txt").exists() or force: mirtk.evaluate_similarity( str(subject_seg), str(self.atlases[i]), Tbins=64, Sbins=64, dofin=str( output_dir.joinpath(f"shapelandmarks_{i}.dof.gz")), table=str(output_dir.joinpath(f"shapenmi_{i}.txt")), ) output_dofs.append( output_dir.joinpath(f"shapelandmarks_{i}.dof.gz")) if output_dir.joinpath(f"shapenmi_{i}.txt").exists(): similarities = np.genfromtxt('{0}/shapenmi_{1}.txt'.format( str(output_dir), i), delimiter=",") nmi += [similarities[1, 5]] else: nmi += [0] except KeyboardInterrupt: raise except Exception: continue if n_top < n_atlases: sortedIndexes = np.array(nmi).argsort()[::-1] for i in range(n_top): top_similar_atlases += [self.atlases[sortedIndexes[i]]] top_atlas_dofs += [output_dofs[sortedIndexes[i]]] else: top_similar_atlases = self.atlases top_atlas_dofs = output_dofs return top_similar_atlases, top_atlas_dofs
def run(self, subject_image: PhaseImage, subject_seg: Segmentation, subject_landmarks: Path, output_dir: Path, n_top: int, force: bool) -> Segmentation: output_path = output_dir.joinpath(subject_seg.path.stem + "_refined.nii.gz") if force or not Segmentation(path=output_path, phase=subject_seg.phase).exists(): tmp_dir = output_dir.joinpath("tmp", str(subject_seg.phase)) tmp_dir.mkdir(exist_ok=True, parents=True) top_atlases, top_dofs = self.select_altases( subject_seg=subject_seg.path, subject_landmarks=subject_landmarks, output_dir=tmp_dir, n_top=n_top, force=force, ) atlas_labels = [] phase = str(subject_seg.phase) for i, (atlas, dof) in enumerate(zip(top_atlases, top_dofs)): if not tmp_dir.joinpath( f"shapeffd_{i}_{str(phase)}.dof.gz").exists() or force: mirtk.register(str(subject_seg), str(atlas), parin=str(self.param_path), dofin=str(dof), dofout=tmp_dir.joinpath( f"shapeffd_{i}_{phase}.dof.gz")) label_path = tmp_dir.joinpath(f"seg_affine_{i}_{phase}.nii.gz") if not label_path.exists() or force: mirtk.transform_image( str(atlas), str(label_path), dofin=str(dof), target=str(subject_image), interp="NN", ) label_path = tmp_dir.joinpath(f"seg_{i}_{phase}.nii.gz") if not label_path.exists() or force: mirtk.transform_image( str(atlas), str(label_path), dofin=str( tmp_dir.joinpath(f"shapeffd_{i}_{phase}.dof.gz")), target=str(subject_image), interp="NN", ) nim = nib.load(str(label_path)) label = nim.get_data() label[label == 4] = 3 nim2 = nib.Nifti1Image(label, nim.affine) nim2.header['pixdim'] = nim.header['pixdim'] nib.save(nim2, str(label_path)) atlas_labels.append(label_path) # apply label fusion labels = sitk.VectorOfImage() for label_path in atlas_labels: label = sitk.ReadImage(str(label_path), imageIO="NiftiImageIO", outputPixelType=sitk.sitkUInt8) labels.push_back(label) voter = sitk.LabelVotingImageFilter() voter.SetLabelForUndecidedPixels(0) fused_label = voter.Execute(labels) sitk.WriteImage(fused_label, str(output_path), imageIO="NiftiImageIO") return Segmentation(path=output_path, phase=subject_seg.phase)
def meshGeneration(subject: Subject, template_dir: Path): print("\n ... Mesh Generation - step [1] -") for phase, segmented_path, segmented_LR_path in zip( ["ED", "ES"], subject.segmented_ed_es, subject.segmented_LR_ed_es ): # extract meshes of lvendo, lvepi, lvmyo, rv and rveip at ED and ES, respectively mirtk.calculate_element_wise( str(segmented_path), "-label", 3, 4, set=255, pad=0, output=str(subject.tmps_dir().joinpath("vtk_RV_{}.nii.gz".format(phase))), ) mirtk.extract_surface( str(subject.tmps_dir().joinpath("vtk_RV_{}.nii.gz".format(phase))), str(subject.vtks_dir().joinpath("RV_{}.vtk".format(phase))), isovalue=120, blur=2, ) mirtk.calculate_element_wise( str(segmented_path), "-label", 3, 4, set=255, pad=0, output=str(subject.tmps_dir().joinpath("vtk_RVepi_{}.nii.gz".format(phase))), ) mirtk.extract_surface( str(subject.tmps_dir().joinpath("vtk_RVepi_{}.nii.gz".format(phase))), str(subject.vtks_dir().joinpath("RVepi_{}.vtk".format(phase))), isovalue=120, blur=2, ) mirtk.calculate_element_wise( str(segmented_path), "-map", 3, 0, 4, 0, output=str(subject.tmps_dir().joinpath("vtk_LV_{}.nii.gz".format(phase))), ) mirtk.calculate_element_wise( str(segmented_path), "-label", 1, set=255, pad=0, output=str(subject.tmps_dir().joinpath("vtk_LVendo_{}.nii.gz".format(phase))), ) mirtk.extract_surface( str(subject.tmps_dir().joinpath("vtk_LVendo_{}.nii.gz".format(phase))), str(subject.vtks_dir().joinpath("LVendo_{}.vtk".format(phase))), isovalue=120, blur=2, ) mirtk.calculate_element_wise( str(segmented_path), "-label", 1, 2, set=255, pad=0, output=str(subject.tmps_dir().joinpath("vtk_LVepi_{}.nii.gz".format(phase))), ) mirtk.extract_surface( str(subject.tmps_dir().joinpath("vtk_LVepi_{}.nii.gz".format(phase))), str(subject.vtks_dir().joinpath("LVepi_{}.vtk".format(phase))), isovalue=120, blur=2, ) mirtk.calculate_element_wise( str(segmented_path), "-label", 2, set=255, pad=0, output=str(subject.tmps_dir().joinpath("vtk_LVmyo_{}.nii.gz".format(phase))), ) mirtk.extract_surface( str(subject.tmps_dir().joinpath("vtk_LVmyo_{}.nii.gz".format(phase))), str(subject.vtks_dir().joinpath("LVmyo_{}.vtk".format(phase))), isovalue=120, blur=2, ) # use landmark to initialise the registration mirtk.register( str(subject.landmark_path), str(template_dir.joinpath("landmarks2.vtk")), model="Rigid", dofout=str(subject.dofs_dir().joinpath("landmarks.dof.gz")), ) ############################################################################### print("\n ... Mesh Generation - step [2] -") for fr in ['ED', 'ES']: mirtk.register_points( "-t", str(subject.vtks_dir().joinpath("RV_{}.vtk".format(fr))), "-s", str(template_dir.joinpath("RV_{}.vtk".format(fr))), "-t", str(subject.vtks_dir().joinpath("LVendo_{}.vtk".format(fr))), "-s", str(template_dir.joinpath("LVendo_{}.vtk".format(fr))), "-t", str(subject.vtks_dir().joinpath("LVepi_{}.vtk".format(fr))), "-s", str(template_dir.joinpath("LVepi_{}.vtk".format(fr))), "-symmetric", dofin=str(subject.dofs_dir().joinpath("landmarks.dof.gz")), dofout=str(subject.tmps_dir().joinpath("{}.dof.gz".format(fr))) ) mirtk.register_points( "-t", str(subject.vtks_dir().joinpath("LVendo_{}.vtk".format(fr))), "-s", str(template_dir.joinpath("LVendo_{}.vtk".format(fr))), "-t", str(subject.vtks_dir().joinpath("LVepi_{}.vtk".format(fr))), "-s", str(template_dir.joinpath("LVepi_{}.vtk".format(fr))), "-symmetric", dofin=str(subject.tmps_dir().joinpath("{}.dof.gz".format(fr))), dofout=str(subject.tmps_dir().joinpath("lv_{}_rreg.dof.gz".format(fr))), ) mirtk.register_points( "-t", str(subject.vtks_dir().joinpath("RV_{}.vtk".format(fr))), "-s", str(template_dir.joinpath("RV_{}.vtk".format(fr))), "-symmetric", dofin=str(subject.tmps_dir().joinpath("{}.dof.gz".format(fr))), dofout=str(subject.tmps_dir().joinpath("rv_{}_rreg.dof.gz".format(fr))), ) ########################################################################### # os.system('ptransformation ' # '{0}/RV_{2}.vtk ' # '{0}/N_RV_{2}.vtk ' # '-dofin {1}/rv_{2}_rreg.dof.gz >/dev/nul ' # .format(vtks_dir, tmps_dir, fr)) mirtk.transform_points( str(subject.vtks_dir().joinpath("RV_{}.vtk".format(fr))), str(subject.vtks_dir().joinpath("N_RV_{}.vtk".format(fr))), dofin=str(subject.tmps_dir().joinpath("rv_{}_rreg.dof.gz".format(fr))), ) # os.system('ptransformation ' # '{0}/RVepi_{2}.vtk ' # '{0}/N_RVepi_{2}.vtk ' # '-dofin {1}/rv_{2}_rreg.dof.gz >/dev/nul ' # .format(vtks_dir, tmps_dir, fr)) mirtk.transform_points( str(subject.vtks_dir().joinpath("RVepi_{}.vtk".format(fr))), str(subject.vtks_dir().joinpath("N_RVepi_{}.vtk".format(fr))), dofin=str(subject.tmps_dir().joinpath("rv_{}_rreg.dof.gz".format(fr))), ) # os.system('ptransformation ' # '{0}/LVendo_{2}.vtk ' # '{0}/N_LVendo_{2}.vtk ' # '-dofin {1}/lv_{2}_rreg.dof.gz >/dev/nul ' # .format(vtks_dir, tmps_dir, fr)) mirtk.transform_points( str(subject.vtks_dir().joinpath("LVendo_{}.vtk".format(fr))), str(subject.vtks_dir().joinpath("N_LVendo_{}.vtk".format(fr))), dofin=str(subject.tmps_dir().joinpath("lv_{}_rreg.dof.gz".format(fr))), ) # os.system('ptransformation ' # '{0}/LVepi_{2}.vtk ' # '{0}/N_LVepi_{2}.vtk ' # '-dofin {1}/lv_{2}_rreg.dof.gz >/dev/nul ' # .format(vtks_dir, tmps_dir, fr)) mirtk.transform_points( str(subject.vtks_dir().joinpath("LVepi_{}.vtk".format(fr))), str(subject.vtks_dir().joinpath("N_LVepi_{}.vtk".format(fr))), dofin=str(subject.tmps_dir().joinpath("lv_{}_rreg.dof.gz".format(fr))), ) # os.system('ptransformation ' # '{0}/LVmyo_{2}.vtk ' # '{0}/N_LVmyo_{2}.vtk ' # '-dofin {1}/lv_{2}_rreg.dof.gz >/dev/nul ' # .format(vtks_dir, tmps_dir, fr)) mirtk.transform_points( str(subject.vtks_dir().joinpath("LVmyo_{}.vtk".format(fr))), str(subject.vtks_dir().joinpath("N_LVmyo_{}.vtk".format(fr))), dofin=str(subject.tmps_dir().joinpath("lv_{}_rreg.dof.gz".format(fr))), ) # os.system('transformation ' # '{0}/vtk_RV_{1}.nii.gz ' # '{0}/N_vtk_RV_{1}.nii.gz ' # '-dofin {0}/lv_{1}_rreg.dof.gz ' # '-invert >/dev/nul ' # .format(tmps_dir, fr)) mirtk.transform_image( str(subject.tmps_dir().joinpath("vtk_RV_{}.nii.gz".format(fr))), str(subject.tmps_dir().joinpath("N_vtk_RV_{}.nii.gz".format(fr))), "-invert", dofin=str(subject.tmps_dir().joinpath("lv_{}_rreg.dof.gz".format(fr))), ) # os.system('transformation ' # '{0}/vtk_LV_{1}.nii.gz ' # '{0}/N_vtk_LV_{1}.nii.gz ' # '-dofin {0}/lv_{1}_rreg.dof.gz ' # '-invert >/dev/nul ' # .format(tmps_dir, fr)) mirtk.transform_image( str(subject.tmps_dir().joinpath("vtk_LV_{}.nii.gz".format(fr))), str(subject.tmps_dir().joinpath("N_vtk_LV_{}.nii.gz".format(fr))), "-invert", dofin=str(subject.tmps_dir().joinpath("lv_{}_rreg.dof.gz".format(fr))), ) ########################################################################### #affine # os.system('areg ' # '{0}/vtk_RV_{3}.nii.gz ' # '{1}/N_vtk_RV_{3}.nii.gz ' # '-dofout {1}/rv_{3}_areg.dof.gz ' # '-parin {2}/segareg.txt >/dev/nul ' # .format(template_dir, tmps_dir, param_dir, fr)) mirtk.smooth_image( str(template_dir.joinpath("vtk_RV_{}.nii.gz".format(fr))), str(subject.tmps_dir().joinpath("smoothed_template_vtk_RV_{}.nii.gz".format(fr))), 1, "-float" ) mirtk.register( str(subject.tmps_dir().joinpath("smoothed_template_vtk_RV_{}.nii.gz".format(fr))), str(subject.tmps_dir().joinpath("N_vtk_RV_{}.nii.gz".format(fr))), model="Affine", dofout=str(subject.tmps_dir().joinpath("rv_{}_areg.dof.gz".format(fr))), parin=str(template_dir.joinpath("segareg.txt")), ) # os.system('areg ' # '{0}/vtk_LV_{3}.nii.gz ' # '{1}/N_vtk_LV_{3}.nii.gz ' # '-dofout {1}/lv_{3}_areg.dof.gz ' # '-parin {2}/segareg.txt >/dev/nul ' # .format(template_dir, tmps_dir, param_dir, fr)) mirtk.register( str(template_dir.joinpath("vtk_LV_{}.nii.gz".format(fr))), str(subject.tmps_dir().joinpath("N_vtk_LV_{}.nii.gz".format(fr))), model="Affine", dofout=str(subject.tmps_dir().joinpath("lv_{}_areg.dof.gz".format(fr))), parin=str(template_dir.joinpath("segareg.txt")), ) #non-rigid # os.system('nreg ' # '{0}/vtk_RV_{3}.nii.gz ' # '{1}/N_vtk_RV_{3}.nii.gz ' # '-dofin {1}/rv_{3}_areg.dof.gz ' # '-dofout {1}/rv_{3}_nreg.dof.gz ' # '-parin {2}/segreg.txt >/dev/nul ' # .format(template_dir, tmps_dir, param_dir, fr)) mirtk.register( str(template_dir.joinpath("vtk_RV_{}.nii.gz".format(fr))), str(subject.tmps_dir().joinpath("N_vtk_RV_{}.nii.gz".format(fr))), model="FFD", dofin=str(subject.tmps_dir().joinpath("rv_{}_areg.dof.gz".format(fr))), dofout=str(subject.tmps_dir().joinpath("rv_{}_nreg.dof.gz".format(fr))), parin=str(template_dir.joinpath("segreg.txt")), ) # os.system('snreg ' # '{0}/RV_{3}.vtk ' # '{1}/N_RV_{3}.vtk ' # '-dofin {2}/rv_{3}_nreg.dof.gz ' # '-dofout {2}/rv{3}ds8.dof.gz ' # '-ds 8 -symmetric >/dev/nul ' # .format(template_dir, vtks_dir, tmps_dir, fr)) mirtk.register( str(template_dir.joinpath("RV_{}.vtk".format(fr))), str(subject.vtks_dir().joinpath("N_RV_{}.vtk".format(fr))), # "-symmetric", "-par", "Point set distance correspondence", "CP", ds=8, model="FFD", dofin=str(subject.tmps_dir().joinpath("rv_{}_nreg.dof.gz".format(fr))), dofout=str(subject.tmps_dir().joinpath("rv{}ds8.dof.gz".format(fr))), ) # # os.system('nreg ' # # '{0}/vtk_LV_{3}.nii.gz ' # # '{1}/N_vtk_LV_{3}.nii.gz ' # # '-dofin {1}/lv_{3}_areg.dof.gz ' # # '-dofout {1}/lv_{3}_nreg.dof.gz ' # # '-parin {2}/segreg.txt >/dev/nul ' # # .format(template_dir, tmps_dir, param_dir, fr)) mirtk.register( str(template_dir.joinpath("vtk_LV_{}.nii.gz".format(fr))), str(subject.tmps_dir().joinpath("N_vtk_LV_{}.nii.gz".format(fr))), model="FFD", dofin=str(subject.tmps_dir().joinpath("lv_{}_areg.dof.gz".format(fr))), dofout=str(subject.tmps_dir().joinpath("lv_{}_nreg.dof.gz".format(fr))), parin=str(template_dir.joinpath("segreg.txt")), ) # os.system('msnreg 2 ' # '{0}/LVendo_{3}.vtk ' # '{0}/LVepi_{3}.vtk ' # '{1}/N_LVendo_{3}.vtk ' # '{1}/N_LVepi_{3}.vtk ' # '-dofin {2}/lv_{3}_nreg.dof.gz ' # '-dofout {2}/lv{3}final.dof.gz ' # '-ds 4 -symmetric >/dev/nul ' # .format(template_dir, vtks_dir, tmps_dir, fr)) mirtk.register( str(template_dir.joinpath("LVendo_{}.vtk".format(fr))), str(subject.vtks_dir().joinpath("N_LVendo_{}.vtk".format(fr))), str(template_dir.joinpath("LVepi_{}.vtk".format(fr))), str(subject.vtks_dir().joinpath("N_LVepi_{}.vtk".format(fr))), # "-symmetric", "-par", "Energy function", "PCD(T o P(1:2:end), P(2:2:end))", model="FFD", dofin=str(subject.tmps_dir().joinpath("lv_{}_nreg.dof.gz".format(fr))), dofout=str(subject.tmps_dir().joinpath("lv{}final.dof.gz".format(fr))), ds=4, ) # same number of points # os.system('cardiacsurfacemap ' # '{0}/LVendo_{3}.vtk ' # '{1}/N_LVendo_{3}.vtk ' # '{2}/lv{3}final.dof.gz ' # '{1}/F_LVendo_{3}.vtk >/dev/nul ' # .format(template_dir, vtks_dir, tmps_dir, fr)) mirtk.match_points( str(template_dir.joinpath("LVendo_{}.vtk".format(fr))), str(subject.vtks_dir().joinpath("N_LVendo_{}.vtk".format(fr))), dofin=str(subject.tmps_dir().joinpath("lv{}final.dof.gz".format(fr))), output=str(subject.vtks_dir().joinpath("F_LVendo_{}.vtk".format(fr))), ) # os.system('cardiacsurfacemap ' # '{0}/LVepi_{3}.vtk ' # '{1}/N_LVepi_{3}.vtk ' # '{2}/lv{3}final.dof.gz ' # '{1}/F_LVepi_{3}.vtk >/dev/nul ' # .format(template_dir, vtks_dir, tmps_dir, fr)) mirtk.match_points( str(template_dir.joinpath("LVepi_{}.vtk".format(fr))), str(subject.vtks_dir().joinpath("N_LVepi_{}.vtk".format(fr))), dofin=str(subject.tmps_dir().joinpath("lv{}final.dof.gz".format(fr))), output=str(subject.vtks_dir().joinpath("F_LVepi_{}.vtk".format(fr))), ) # os.system('ptransformation ' # '{0}/LVmyo_{3}.vtk ' # '{1}/F_LVmyo_{3}.vtk ' # '-dofin {2}/lv{3}final.dof.gz >/dev/nul ' # .format(template_dir, vtks_dir, tmps_dir, fr)) mirtk.transform_points( str(template_dir.joinpath("LVmyo_{}.vtk".format(fr))), str(subject.vtks_dir().joinpath("F_LVmyo_{}.vtk".format(fr))), dofin=str(subject.tmps_dir().joinpath("lv{}final.dof.gz".format(fr))), ) # os.system('cardiacsurfacemap ' # '{0}/RV_{3}.vtk ' # '{1}/N_RV_{3}.vtk ' # '{2}/rv{3}ds8.dof.gz ' # '{1}/C_RV_{3}.vtk >/dev/nul ' # .format(template_dir, vtks_dir, tmps_dir, fr)) mirtk.match_points( str(template_dir.joinpath("RV_{}.vtk".format(fr))), str(subject.vtks_dir().joinpath("N_RV_{}.vtk".format(fr))), dofin=str(subject.tmps_dir().joinpath("rv{}ds8.dof.gz".format(fr))), output=str(subject.vtks_dir().joinpath("C_RV_{}.vtk".format(fr))), ) ########################################################################### # os.system('cp {0}/F_LVendo_{1}.vtk {0}/S_LVendo_{1}.vtk'.format(vtks_dir, fr)) # os.system('cp {0}/F_LVepi_{1}.vtk {0}/S_LVepi_{1}.vtk'.format(vtks_dir, fr)) # os.system('cp {0}/F_LVmyo_{1}.vtk {0}/S_LVmyo_{1}.vtk'.format(vtks_dir, fr)) # os.system('cp {0}/F_LVmyo_{1}.vtk {0}/C_LVmyo_{1}.vtk'.format(vtks_dir, fr)) # os.system('cp {0}/F_LVmyo_{1}.vtk {0}/W_LVmyo_{1}.vtk'.format(vtks_dir, fr)) # os.system('cp {0}/C_RV_{1}.vtk {0}/S_RV_{1}.vtk'.format(vtks_dir, fr)) # os.system('cp {0}/C_RV_{1}.vtk {0}/W_RV_{1}.vtk'.format(vtks_dir, fr)) shutil.copy( str(subject.vtks_dir().joinpath("F_LVendo_{}.vtk".format(fr))), subject.vtks_dir().joinpath("S_LVendo_{}.vtk".format(fr)) ) shutil.copy( str(subject.vtks_dir().joinpath("F_LVepi_{}.vtk".format(fr))), subject.vtks_dir().joinpath("S_LVepi_{}.vtk".format(fr)) ) shutil.copy( str(subject.vtks_dir().joinpath("F_LVmyo_{}.vtk".format(fr))), subject.vtks_dir().joinpath("S_LVmyo_{}.vtk".format(fr)) ) shutil.copy( str(subject.vtks_dir().joinpath("F_LVmyo_{}.vtk".format(fr))), subject.vtks_dir().joinpath("C_LVmyo_{}.vtk".format(fr)) ) shutil.copy( str(subject.vtks_dir().joinpath("F_LVmyo_{}.vtk".format(fr))), subject.vtks_dir().joinpath("W_LVmyo_{}.vtk".format(fr)) ) shutil.copy( str(subject.vtks_dir().joinpath("C_RV_{}.vtk".format(fr))), subject.vtks_dir().joinpath("S_RV_{}.vtk".format(fr)) ) shutil.copy( str(subject.vtks_dir().joinpath("C_RV_{}.vtk".format(fr))), subject.vtks_dir().joinpath("W_RV_{}.vtk".format(fr)) ) print("\n ... Mesh Generation - step [3] -") ########################################################################### # compute the quantities of the heart with respect to template # os.system('cardiacwallthickness ' # '{0}/F_LVendo_{1}.vtk ' # '{0}/F_LVepi_{1}.vtk ' # '-myocardium ' # '{0}/W_LVmyo_{1}.vtk >/dev/nul ' # .format(vtks_dir, fr)) mirtk.evaluate_distance( str(subject.vtks_dir().joinpath("F_LVendo_{}.vtk".format(fr))), str(subject.vtks_dir().joinpath("F_LVepi_{}.vtk".format(fr))), name="WallThickness", ) # os.system('cardiacenlargedistance ' # '{0}/S_LVendo_{2}.vtk ' # '{0}/S_LVepi_{2}.vtk ' # '{1}/LVendo_{2}.vtk ' # '{1}/LVepi_{2}.vtk ' # '-myocardium ' # '{0}/S_LVmyo_{2}.vtk >/dev/nul ' # .format(vtks_dir, template_dir, fr)) mirtk.evaluate_distance( str(subject.vtks_dir().joinpath("S_LVendo_{}.vtk".format(fr))), str(template_dir.joinpath("LVendo_{}.vtk".format(fr))), name="WallThickness", ) mirtk.evaluate_distance( str(subject.vtks_dir().joinpath("S_LVepi_{}.vtk".format(fr))), str(template_dir.joinpath("LVepi_{}.vtk".format(fr))), name="WallThickness", ) # os.system('DiscreteCurvatureEstimator ' # '{0}/C_LVmyo_{1}.vtk ' # '{0}/FC_LVmyo_{1}.vtk >/dev/nul ' # .format(vtks_dir, fr)) # # os.system('cardiaccurvature ' # '{0}/FC_LVmyo_{1}.vtk ' # '{0}/C_LVmyo_{1}.vtk >/dev/nul ' # '-smooth 64' # .format(vtks_dir, fr)) # mirtk.decimate_surface( # str(subject.vtks_dir().joinpath("C_LVmyo_{}.vtk".format(fr))), # str(subject.vtks_dir().joinpath("FC_LVmyo_{}.vtk".format(fr))), # ) mirtk.calculate_surface_attributes( str(subject.vtks_dir().joinpath("C_LVmyo_{}.vtk".format(fr))), str(subject.vtks_dir().joinpath("C_LVmyo_{}.vtk".format(fr))), smooth_iterations=64, ) # os.system('DiscreteCurvatureEstimator ' # '{0}/C_RV_{1}.vtk ' # '{0}/FC_RV_{1}.vtk >/dev/nul ' # .format(vtks_dir, fr)) # # os.system('cardiaccurvature ' # '{0}/FC_RV_{1}.vtk ' # '{0}/C_RV_{1}.vtk ' # '-smooth 64 >/dev/nul ' # .format(vtks_dir, fr)) # mirtk.decimate_surface( # str(subject.vtks_dir().joinpath("C_RV_{}.vtk".format(fr))), # str(subject.vtks_dir().joinpath("FC_RV_{}.vtk".format(fr))), # ) mirtk.calculate_surface_attributes( str(subject.vtks_dir().joinpath("C_RV_{}.vtk".format(fr))), str(subject.vtks_dir().joinpath("C_RV_{}.vtk".format(fr))), smooth_iterations=64, ) # os.system('sevaluation ' # '{0}/S_RV_{2}.vtk ' # '{1}/RV_{2}.vtk ' # '-scalar ' # '-signed >/dev/nul ' # .format(vtks_dir, template_dir, fr)) mirtk.evaluate_distance( str(subject.vtks_dir().joinpath("S_RV_{}.vtk".format(fr))), str(template_dir.joinpath("RV_{}.vtk".format(fr))), "-normal", name="WallThickness", ) # os.system('cardiacwallthickness ' # '{0}/W_RV_{1}.vtk ' # '{0}/N_RVepi_{1}.vtk >/dev/nul ' # .format(vtks_dir, fr)) mirtk.evaluate_distance( str(subject.vtks_dir().joinpath("W_RV_{}.vtk".format(fr))), str(subject.vtks_dir().joinpath("N_RVepi_{}.vtk".format(fr))), name="WallThickness", ) ########################################################################### # os.system('vtk2txt {0}/C_RV_{1}.vtk {2}/rv_{1}_curvature.txt'.format(vtks_dir, fr, subject_dir)) # os.system('vtk2txt {0}/W_RV_{1}.vtk {2}/rv_{1}_wallthickness.txt'.format(vtks_dir, fr, subject_dir)) # os.system('vtk2txt {0}/S_RV_{1}.vtk {2}/rv_{1}_signeddistances.txt'.format(vtks_dir, fr, subject_dir)) # os.system('vtk2txt {0}/W_LVmyo_{1}.vtk {2}/lv_myo{1}_wallthickness.txt'.format(vtks_dir, fr, subject_dir)) # os.system('vtk2txt {0}/C_LVmyo_{1}.vtk {2}/lv_myo{1}_curvature.txt'.format(vtks_dir, fr, subject_dir)) # os.system('vtk2txt {0}/S_LVmyo_{1}.vtk {2}/lv_myo{1}_signeddistances.txt'.format(vtks_dir, fr, subject_dir)) if fr == 'ED': fr_ = 'ed' if fr == 'ES': fr_ = 'es' # os.system('vtk2txt {0}/C_RV_{1}.vtk {2}/rv_{3}_curvature.txt'.format(vtks_dir, fr, subject_dir, fr_)) # os.system('vtk2txt {0}/W_RV_{1}.vtk {2}/rv_{3}_wallthickness.txt'.format(vtks_dir, fr, subject_dir, fr_)) # os.system('vtk2txt {0}/S_RV_{1}.vtk {2}/rv_{3}_signeddistances.txt'.format(vtks_dir, fr, subject_dir, fr_)) mirtk.convert_pointset( str(subject.vtks_dir().joinpath("C_RV_{}.vtk".format(fr))), str(subject.dir.joinpath("rv_{}_curvature.txt".format(fr_))), ) mirtk.convert_pointset( str(subject.vtks_dir().joinpath("W_RV_{}.vtk".format(fr))), str(subject.dir.joinpath("rv_{}_wallthickness.txt".format(fr_))), ) mirtk.convert_pointset( str(subject.vtks_dir().joinpath("S_RV_{}.vtk".format(fr))), str(subject.dir.joinpath("rv_{}_signeddistances.txt".format(fr_))), ) ############################################################################################################ # os.system('vtk2txt {0}/W_LVmyo_{1}.vtk {2}/lv_myo{3}_wallthickness.txt'.format(vtks_dir, fr, subject_dir, fr_)) # os.system('vtk2txt {0}/C_LVmyo_{1}.vtk {2}/lv_myo{3}_curvature.txt'.format(vtks_dir, fr, subject_dir, fr_)) # os.system('vtk2txt {0}/S_LVmyo_{1}.vtk {2}/lv_myo{3}_signeddistances.txt'.format(vtks_dir, fr, subject_dir, fr_)) mirtk.convert_pointset( str(subject.vtks_dir().joinpath("W_LVmyo_{}.vtk".format(fr))), str(subject.dir.joinpath("lv_myo{}_wallthickness.txt".format(fr_))), ) mirtk.convert_pointset( str(subject.vtks_dir().joinpath("C_LVmyo_{}.vtk".format(fr))), str(subject.dir.joinpath("lv_myo{}_curvature.txt".format(fr_))), ) mirtk.convert_pointset( str(subject.vtks_dir().joinpath("S_LVmyo_{}.vtk".format(fr))), str(subject.dir.joinpath("lv_myo{}_signeddistances.txt".format(fr_))), )
def run(self, cine: CineImages, ed_segmentation: Segmentation, landmark_path: Path, ED_mesh: PhaseMesh, output_dir: Path, overwrite: bool = False): # Forward image registration forward_dofs = {} output_dir.mkdir(parents=True, exist_ok=True) dof_dir = output_dir.joinpath("dof") dof_dir.mkdir(parents=True, exist_ok=True) for fr in tqdm(range(1, len(cine))): target = cine[fr - 1] source = cine[fr] par = self.ffd_motion_cfg dof_output = dof_dir.joinpath("ffd_{:02d}_to_{:02d}.dof.gz".format( fr - 1, fr)) if not dof_output.exists(): mirtk.register(str(target), str(source), parin=str(par), dofout=str(dof_output)) forward_dofs[fr] = dof_output # Compose inter-frame transformation fields # print("\n ... Compose inter-frame transformation fields") compose_dofs = {} for fr in tqdm(range(2, len(cine))): dof_out = dof_dir.joinpath( "ffd_comp_00_to_{:02d}.dof.gz".format(fr)) dofs = [str(forward_dofs[k]) for k in range(1, fr + 1)] if not dof_out.exists(): mirtk.compose_dofs(*dofs, str(dof_out)) compose_dofs[fr] = dof_out # Refine motion fields # Composition of inter-frame motion fields can lead to accumulative errors. # At this step, we refine the motion fields by re-registering the n-th frame with the ED frame. refine_dofs = {} print("\n ... Refine motion fields") for fr in tqdm(range(2, len(cine))): target = cine[0] source = cine[fr] dofin = compose_dofs[fr] dofout = dof_dir.joinpath("ffd_00_to_{:02d}.dof.gz".format(fr)) if not dofout.exists(): mirtk.register(str(target), str(source), parin=str(self.ffd_refine_cfg), dofin=str(dofin), dofout=str(dofout)) refine_dofs[fr] = dofout refine_dofs[1] = forward_dofs[1] landmark_init_dof = dof_dir.joinpath("landmarks.dof.gz") if not landmark_init_dof.exists() or overwrite: mirtk.register( str(landmark_path), str(self.template.landmark), model="Rigid", dofout=str(landmark_init_dof), ) lv_endo_frame_0 = self.transform_mesh( source_mesh=self.template.lv_endo(Phase.ED), target_mesh=ED_mesh.lv.endocardium, landmark_init_dof=landmark_init_dof, output_dir=output_dir.joinpath("lv", "endo"), overwrite=overwrite, ) # Transform the mesh print("\n ... Transform the LV endo mesh") self.motion_mesh(frame_0_mesh=lv_endo_frame_0, motion_dofs=refine_dofs, output_dir=output_dir.joinpath("lv", "endo"), overwrite=overwrite) lv_epi_frame_0 = self.transform_mesh( source_mesh=self.template.lv_epi(Phase.ED), target_mesh=ED_mesh.lv.epicardium, landmark_init_dof=landmark_init_dof, output_dir=output_dir.joinpath("lv", "epi"), overwrite=overwrite, ) # Transform the mesh print("\n ... Transform the LV epi mesh") self.motion_mesh(frame_0_mesh=lv_epi_frame_0, motion_dofs=refine_dofs, output_dir=output_dir.joinpath("lv", "epi"), overwrite=overwrite) rv_frame_0 = self.transform_mesh( source_mesh=self.template.rv(Phase.ED), target_mesh=ED_mesh.rv.rv, landmark_init_dof=landmark_init_dof, output_dir=output_dir.joinpath("rv"), overwrite=overwrite, ) # Transform the mesh print("\n ... Transform the RV mesh") self.motion_mesh(frame_0_mesh=rv_frame_0, motion_dofs=refine_dofs, output_dir=output_dir.joinpath("rv"), overwrite=overwrite) output_dir.joinpath("seg").mkdir(parents=True, exist_ok=True) for fr in tqdm(range(0, len(cine) - 1)): # os.system('mirtk transform-image {0}/lvsa_seg_fr00.nii.gz ' # '{2}/lvsa_seg_wrap_ffd_fr{1:02d}.nii.gz ' # '-dofin {3}/ffd_00_to_{1:02d}.dof.gz ' # '-invert -interp NN' # .format(seg_slice_path, fr, pred_path, dof_path)) mirtk.transform_image( str(ed_segmentation), str(output_dir.joinpath("seg").joinpath(f"lvsa_{fr}.nii.gz")), "-invert", "-v", interp="NN", dofin=refine_dofs[fr + 1])
def transform_mesh(source_mesh: MeshResource, target_mesh: MeshResource, landmark_init_dof: Path, output_dir: Path, overwrite: bool = False) -> MeshResource: output_dir.mkdir(parents=True, exist_ok=True) temp_dir = output_dir.joinpath("temp") output_dir.joinpath("vtk").mkdir(parents=True, exist_ok=True) dof_dir = temp_dir.joinpath("dof") dof_dir.mkdir(parents=True, exist_ok=True) rigid_dof = dof_dir.joinpath("srreg.dof.gz") affine_dof = dof_dir.joinpath("sareg.dof.gz") nonrigid_dof = dof_dir.joinpath("snreg.dof.gz") temp_srreg_vtk = MeshResource(temp_dir.joinpath("srreg.vtk")) transformed_vtk = MeshResource(output_dir.joinpath("vtk", "fr00.vtk")) if not rigid_dof.exists() or overwrite: mirtk.register_points( "-t", str(target_mesh), "-s", str(source_mesh), "-symmetric", dofin=str(landmark_init_dof), dofout=str(rigid_dof), ) if not temp_srreg_vtk.exists() or overwrite: mirtk.transform_points( str(source_mesh), str(temp_srreg_vtk), "-invert", dofin=str(rigid_dof), ) if not affine_dof.exists() or overwrite: mirtk.register_points( "-t", str(temp_srreg_vtk), "-s", str(target_mesh), "-symmetric", model="Affine", dofout=str(affine_dof), ) if not nonrigid_dof.exists() or overwrite: mirtk.register( str(temp_srreg_vtk), str(target_mesh), "-par", "Point set distance correspondence", "CP", ds=20, model="FFD", dofin=str(affine_dof), dofout=str(nonrigid_dof), ) if not transformed_vtk.exists() or overwrite: mirtk.transform_points( str(temp_srreg_vtk), str(transformed_vtk), dofin=str(nonrigid_dof), ) return transformed_vtk