def save_registration_results(aff_trans, params): r''' Warp the moving image using the obtained affine transform ''' warp_dir = params.warp_dir base_static = getBaseFileName(params.static) static_nib = nib.load(params.static) static = static_nib.get_data().squeeze().astype(np.float64) static_affine = static_nib.get_affine() static_shape = np.array(static.shape, dtype=np.int32) base_moving = getBaseFileName(params.moving) moving_nib = nib.load(params.moving) moving = moving_nib.get_data().squeeze().astype(np.float64) moving_affine = moving_nib.get_affine() moving_shape = np.array(moving.shape, dtype=np.int32) dim = len(static.shape) static_affine = static_affine[:(dim + 1), :(dim + 1)] moving_affine = moving_affine[:(dim + 1), :(dim + 1)] warped = np.array(aff_trans.transform(moving)) img_affine = np.eye(4,4) img_affine[:(dim + 1), :(dim + 1)] = static_affine[...] img_warped = nib.Nifti1Image(warped, img_affine) img_warped.to_filename('warpedAff_'+base_moving+'_'+base_static+'.nii.gz') #---warp all volumes in the warp directory using NN interpolation names = [os.path.join(warp_dir, name) for name in os.listdir(warp_dir)] for name in names: to_warp_nib = nib.load(name) to_warp_affine = to_warp_nib.get_affine() img_affine = to_warp_affine[:(dim + 1), :(dim + 1)] to_warp = to_warp_nib.get_data().squeeze().astype(np.int32) base_warp = getBaseFileName(name) print(static.dtype, static_affine.dtype, to_warp.dtype, img_affine.dtype) warped = np.array(aff_trans.transform(to_warp, interp='nearest')) img_affine = np.eye(4,4) img_affine[:(dim + 1), :(dim + 1)] = static_affine[...] img_warped = nib.Nifti1Image(warped, img_affine) img_warped.to_filename('warpedAff_'+base_warp+'_'+base_static+'.nii.gz') #---now the jaccard indices if os.path.exists('jaccard_pairs.lst'): with open('jaccard_pairs.lst','r') as f: for line in f.readlines(): aname, bname, cname= line.strip().split() abase = getBaseFileName(aname) bbase = getBaseFileName(bname) aname = 'warpedAff_'+abase+'_'+bbase+'.nii.gz' if os.path.exists(aname) and os.path.exists(cname): compute_jaccard(cname, aname, False) compute_target_overlap(cname, aname, False) else: print('Pair not found ['+cname+'], ['+aname+']') #---finally, the optional output oname = base_moving+'_'+base_static+'Affine.txt' np.savetxt(oname, aff_trans.affine)
def compute_target_overlap(aname, bname, keep_existing = True): baseA=getBaseFileName(aname) baseB=getBaseFileName(bname) oname="t_overlap_"+baseA+"_"+baseB+".txt" if keep_existing and os.path.exists(oname): print('Target overlap overlap found. Skipped computation.') scores=np.loadtxt(oname) return scores nib_A=nib.load(aname) affineA=nib_A.get_affine() A=nib_A.get_data().squeeze().astype(np.int32) A=np.copy(A, order='C') print("A range:",A.min(), A.max()) nib_B=nib.load(bname) #newB=nib.Nifti1Image(nib_B.get_data(),affineA) #newB.to_filename(bname) B=nib_B.get_data().squeeze().astype(np.int32) B=np.copy(B, order='C') print("B range:",B.min(), B.max()) scores=np.array(evaluation.compute_target_overlap(A,B)) print("Target overlap range:",scores.min(), scores.max()) np.savetxt(oname,scores) return scores
def compute_jaccard(aname, bname, keep_existing = True): baseA=getBaseFileName(aname) baseB=getBaseFileName(bname) oname="jaccard_"+baseA+"_"+baseB+".txt" if keep_existing and os.path.exists(oname): print('Jaccard overlap found. Skipped computation.') jaccard=np.loadtxt(oname) return jaccard nib_A=nib.load(aname) affineA=nib_A.get_affine() A=nib_A.get_data().squeeze().astype(np.int32) A=np.copy(A, order='C') print("A range:",A.min(), A.max()) nib_B=nib.load(bname) #newB=nib.Nifti1Image(nib_B.get_data(),affineA) #newB.to_filename(bname) B=nib_B.get_data().squeeze().astype(np.int32) B=np.copy(B, order='C') print("B range:",B.min(), B.max()) jaccard=np.array(evaluation.compute_jaccard(A,B)) print("Jaccard range:",jaccard.min(), jaccard.max()) np.savetxt(oname,jaccard) return jaccard
def save_registration_results(mapping, params, mapping2=None): r''' Warp the target image using the obtained deformation field ''' fixed = nib.load(params.reference) fixed_affine = fixed.get_affine() reference_shape = np.array(fixed.shape, dtype=np.int32) warp_dir = params.warp_dir base_moving = getBaseFileName(params.target) base_fixed = getBaseFileName(params.reference) moving = nib.load(params.target) moving_affine = moving.get_affine() moving = moving.get_data().squeeze().astype(np.float64) moving = moving.copy(order='C') if mapping2 is None: warped = np.array(mapping.transform(moving, 'linear')) else: # Warp by composition: mapping(mapping2_inv(x)) # mapping is static to intermediate # mapping2 is moving to intermediate # The final composition is phi1(phi2(x)) phi1 = mapping2.get_backward_field() # from intermediate to moving phi2 = mapping.get_forward_field() # from static to intermediate A = None # We have a post-align here (phi2 is forward-field of an inverse) B = fixed_affine # grid-to-space of phi2's domain (static domain) C = np.linalg.inv(moving_affine).dot(mapping2.prealign.dot(mapping.prealign_inv)) D = mapping2.prealign.dot(mapping.prealign_inv) E = np.linalg.inv(moving_affine) warped = vfu.warp_with_composition_trilinear(phi1, phi2, A, B, C, D, E, moving.astype(floating), reference_shape) img_warped = nib.Nifti1Image(warped, fixed_affine) img_warped.to_filename('warpedDiff_'+base_moving+'_'+base_fixed+'.nii.gz') #---warp all volumes in the warp directory using NN interpolation names = [os.path.join(warp_dir, name) for name in os.listdir(warp_dir)] for name in names: to_warp = nib.load(name).get_data().squeeze().astype(np.int32) to_warp = to_warp.copy(order='C') base_warp = getBaseFileName(name) if mapping2 is None: warped = np.array(mapping.transform(to_warp, 'nearest')).astype(np.int16) else: # Warp by composition: mapping(mapping2_inv(x)) warped = np.array(vfu.warp_with_composition_nn(phi1, phi2, A, B, C, D, E, to_warp.astype(np.int32), reference_shape)).astype(np.int16) img_warped = nib.Nifti1Image(warped, fixed_affine) img_warped.to_filename('warpedDiff_'+base_warp+'_'+base_fixed+'.nii.gz') #---now the jaccard indices if os.path.exists('jaccard_pairs.lst'): with open('jaccard_pairs.lst','r') as f: for line in f.readlines(): aname, bname, cname= line.strip().split() abase = getBaseFileName(aname) bbase = getBaseFileName(bname) aname = 'warpedDiff_'+abase+'_'+bbase+'.nii.gz' if os.path.exists(aname) and os.path.exists(cname): compute_jaccard(cname, aname, False) compute_target_overlap(cname, aname, False) else: print('Pair not found ['+cname+'], ['+aname+']') #---finally, the optional output if mapping2 is None: if params.output_list == None: return if 'lattice' in params.output_list: save_deformed_lattice_3d( mapping.forward, 'latticeDispDiff_'+base_moving+'_'+base_fixed+'.nii.gz') if 'inv_lattice' in params.output_list: save_deformed_lattice_3d( mapping.backward, 'invLatticeDispDiff_'+base_moving+'_'+base_fixed+'.nii.gz') if 'displacement' in params.output_list: np.save('dispDiff_'+base_moving+'_'+base_fixed+'.npy', mapping.forward) if 'inverse' in params.output_list: np.save('invDispDiff_'+base_moving+'_'+base_fixed+'.npy', mapping.backward)
def create_semi_synthetic(params): r""" Create semi-synthetic image using real_mod1 as anatomy and tmp_mod2 template as intensity model Template tmp_mod1 is registered towards real_mod1 (which are assumed of the same modality) using SyN-CC. The transformation is applied to template tmp_mod2 (which is assumed to be perfectly aligned with tmp_mod1). The transfer function is computed from real_mod1 to warped tmp_mod2 and applied to real_mod1. """ real_mod1 = params.real base_fixed = getBaseFileName(real_mod1) tmp_mod1 = params.template prealign_name = params.prealign tmp_mod2_list = [os.path.join(params.warp_dir, name) for name in os.listdir(params.warp_dir)] tmp_mod2_list = [tmp_mod1] + tmp_mod2_list # Check if all warpings are already done warp_done = os.path.isfile("mask_" + base_fixed + ".nii.gz") if warp_done: for tmp_mod2 in tmp_mod2_list: base_moving = getBaseFileName(tmp_mod2) wname = "warpedDiff_" + base_moving + "_" + base_fixed if real_mod1[-3:] == "img": # Analyze wname += ".img" else: wname += ".nii.gz" if not os.path.isfile(wname): warp_done = False break # Load input images real_nib = nib.load(real_mod1) real_aff = real_nib.get_affine() real = real_nib.get_data().squeeze() if real_mod1[-3:] == "img": # Analyze: move reference from center to corner offset = real_aff[:3, :3].dot(np.array(real.shape) // 2) real_aff[:3, 3] += offset t_mod1_nib = nib.load(tmp_mod1) t_mod1_aff = t_mod1_nib.get_affine() t_mod1 = t_mod1_nib.get_data().squeeze() if tmp_mod1[-3:] == "img": # Analyze: move reference from center to corner offset = t_mod1_aff[:3, :3].dot(np.array(t_mod1.shape) // 2) t_mod1_aff[:3, 3] += offset # Load pre-align matrix print("Pre-align:", prealign_name) if not prealign_name: prealign = np.eye(4) else: if real_mod1[-3:] == "img": # Analyze ref_coordinate_system = "LAS" else: # DICOM ref_coordinate_system = "LPS" if tmp_mod1[-3:] == "img": # Analyze tgt_coordinate_system = "LAS" else: # DICOM tgt_coordinate_system = "LPS" prealign = readAntsAffine(prealign_name, ref_coordinate_system, tgt_coordinate_system) # Configure CC metric sigma_diff = 1.7 radius = 4 similarity_metric = metrics.CCMetric(3, sigma_diff, radius) # Configure optimizer opt_iter = [100, 100, 50] step_length = 0.25 opt_tol = 1e-5 inv_iter = 20 inv_tol = 1e-3 ss_sigma_factor = 0.2 if not warp_done: syn = imwarp.SymmetricDiffeomorphicRegistration( similarity_metric, opt_iter, step_length, ss_sigma_factor, opt_tol, inv_iter, inv_tol, callback=None ) # Run registration syn.verbosity = VerbosityLevels.DEBUG mapping = syn.optimize(real, t_mod1, real_aff, t_mod1_aff, prealign) # Save the warped template (so we can visually check the registration result) warped = mapping.transform(t_mod1) base_moving = getBaseFileName(tmp_mod1) oname = "warpedDiff_" + base_moving + "_" + base_fixed if real_mod1[-3:] == "img": # Analyze oname += ".img" else: oname += ".nii.gz" real[...] = warped[...] real_nib.to_filename(oname) mask = (t_mod1 > 0).astype(np.int32) wmask = mapping.transform(mask, "nearest") wmask_nib = nib.Nifti1Image(wmask, t_mod1_aff) wmask_nib.to_filename("mask_" + base_fixed + ".nii.gz") else: wmask_nib = nib.load("mask_" + base_fixed + ".nii.gz") wmask = wmask_nib.get_data().squeeze() # Compute and save the semi-synthetic images in different modalities for tmp_mod2 in tmp_mod2_list: print("Warping: " + tmp_mod2) t_mod2_nib = nib.load(tmp_mod2) t_mod2_aff = t_mod2_nib.get_affine() t_mod2 = t_mod2_nib.get_data().squeeze() base_moving = getBaseFileName(tmp_mod2) oname = base_moving + "_" + base_fixed if real_mod1[-3:] == "img": # Analyze oname += ".img" else: oname += ".nii.gz" if not warp_done: # Save warped image warped = mapping.transform(t_mod2) wnib = nib.Nifti1Image(warped, t_mod2_aff) wnib.to_filename("warpedDiff_" + oname) else: wnib = nib.load("warpedDiff_" + oname) warped = wnib.get_data().squeeze() real_nib = nib.load(real_mod1) real = real_nib.get_data().squeeze() use_density_estimation = True nbins = 100 if use_density_estimation: print("Using density sampling.") oname = "ssds_" + oname # Compute marginal distributions densities = np.array(compute_densities(real.astype(np.int32), warped.astype(np.float64), nbins, wmask)) # Sample the marginal distributions real[...] = create_ss_de(real.astype(np.int32), densities) else: print("Using mean transfer.") oname = "ssmt_" + oname # Compute transfer function means, vars = get_mean_transfer(real, warped) # Apply transfer to real real[...] = means[real] # Save semi_synthetic real_nib.to_filename(oname)