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)
Esempio n. 2
0
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
Esempio n. 3
0
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
Esempio n. 4
0
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)