def testEstimateMonomodalDiffeomorphicField3DMultiScale(lambdaParam):
    fnameMoving = 'data/affineRegistered/templateT1ToIBSR01T1.nii.gz'
    fnameFixed = 'data/t1/IBSR18/IBSR_01/IBSR_01_ana_strip.nii.gz'
    moving = nib.load(fnameMoving)
    fixed = nib.load(fnameFixed)
    moving = moving.get_data().squeeze().astype(np.float64)
    fixed = fixed.get_data().squeeze().astype(np.float64)
    moving = np.copy(moving, order='C')
    fixed = np.copy(fixed, order='C')
    moving = (moving - moving.min()) / (moving.max() - moving.min())
    fixed = (fixed - fixed.min()) / (fixed.max() - fixed.min())
    level = 3
    #maskMoving=np.ones_like(moving)
    #maskFixed=np.ones_like(fixed)
    movingPyramid = [
        img for img in rcommon.pyramid_gaussian_3D(moving, level,
                                                   np.ones_like(moving))
    ]
    fixedPyramid = [
        img for img in rcommon.pyramid_gaussian_3D(fixed, level,
                                                   np.ones_like(fixed))
    ]
    rcommon.plotOverlaidPyramids3DCoronal(movingPyramid, fixedPyramid)
    #maxOuterIter=[100,100,100,100,100,100,100,100,100]
    maxOuterIter = [3, 3, 3, 3, 3, 3, 3, 3, 3]
    #maxOuterIter=[10,20,50,100, 100, 100]
    displacement = estimateMonomodalDiffeomorphicField3DMultiScale(
        movingPyramid, fixedPyramid, lambdaParam, maxOuterIter, 0, None)
    warped = tf.warp_volume(movingPyramid[0], displacement)
    np.save('displacement_templateT1ToIBSR01T1_diff.npy', displacement)
    np.save('warped_templateT1ToIBSR01T1_diff.npy', warped)
 def warp_backward(self, image):
     r'''
     Applies this transformation in the backward direction to the given
     image using tri-linear interpolation
     '''
     if len(image.shape) == 3:
         if image.dtype is np.dtype('int32'):
             warped = np.array(
                 tf.warp_discrete_volumeNN(
                     image, self.backward, self.affine_post_inv,
                     self.affine_pre_inv))
         elif image.dtype is np.dtype('float64'):
             warped = np.array(
                 tf.warp_volume(
                     image, self.backward, self.affine_post_inv,
                     self.affine_pre_inv))
     else:
         if image.dtype is np.dtype('int32'):
             warped = np.array(
                 tf.warp_discrete_imageNN(
                     image, self.backward, self.affine_post_inv,
                     self.affine_pre_inv))
         elif image.dtype is np.dtype('float64'):
             warped = np.array(
                 tf.warp_image(
                     image, self.backward, self.affine_post_inv,
                     self.affine_pre_inv))
     return warped
Exemple #3
0
def saveDeformedLattice3D(displacement, oname):
    minVal, maxVal=tf.get_displacement_range(displacement, None)
    sh=np.array([np.ceil(maxVal[0]),np.ceil(maxVal[1]),np.ceil(maxVal[2])], dtype=np.int32)
    L=np.array(rcommon.drawLattice3D(sh, 10))
    warped=np.array(tf.warp_volume(L, displacement, np.eye(4))).astype(np.int16)
    img=nib.Nifti1Image(warped, np.eye(4))
    img.to_filename(oname)
Exemple #4
0
def saveDeformedLattice3D(displacement, oname):
    minVal, maxVal = tf.get_displacement_range(displacement, None)
    sh = np.array([np.ceil(maxVal[0]),
                   np.ceil(maxVal[1]),
                   np.ceil(maxVal[2])],
                  dtype=np.int32)
    L = np.array(rcommon.drawLattice3D(sh, 10))
    warped = np.array(tf.warp_volume(L, displacement,
                                     np.eye(4))).astype(np.int16)
    img = nib.Nifti1Image(warped, np.eye(4))
    img.to_filename(oname)
Exemple #5
0
def save_deformed_lattice_3d(displacement, oname):
    r'''
    Applies the given displacement to a regular lattice and saves the resulting
    image to a Nifti file with the given name
    '''
    min_val, max_val = tf.get_displacement_range(displacement, None)
    shape = np.array([np.ceil(max_val[0]), np.ceil(max_val[1]),
                  np.ceil(max_val[2])], dtype = np.int32)
    lattice = np.array(rcommon.drawLattice3D(shape, 10))
    warped = np.array(tf.warp_volume(lattice, displacement)).astype(np.int16)
    img = nib.Nifti1Image(warped, np.eye(4))
    img.to_filename(oname)
def estimateNewMonomodalDiffeomorphicField3D(moving,
                                             fixed,
                                             lambdaParam,
                                             maxOuterIter,
                                             previousDisplacement,
                                             reportProgress=False):
    '''
    Warning: in the monomodal case, the parameter lambda must be significantly lower than in the multimodal case. Try lambdaParam=1,
    as opposed as lambdaParam=150 used in the multimodal case
    '''
    innerTolerance = 1e-3
    outerTolerance = 1e-3
    displacement = np.zeros(shape=(moving.shape) + (3, ), dtype=np.float64)
    residuals = np.zeros(shape=(moving.shape), dtype=np.float64)
    gradientField = np.empty(shape=(moving.shape) + (3, ), dtype=np.float64)
    totalDisplacement = np.zeros(shape=(moving.shape) + (3, ),
                                 dtype=np.float64)
    if (previousDisplacement != None):
        totalDisplacement[...] = previousDisplacement
    outerIter = 0
    while (outerIter < maxOuterIter):
        outerIter += 1
        if (reportProgress):
            print 'Iter:', outerIter, '/', maxOuterIter
        warped = np.array(tf.warp_volume(moving, totalDisplacement))
        sigmaField = np.ones_like(warped, dtype=np.float64)
        deltaField = fixed - warped
        g0, g1, g2 = sp.gradient(warped)
        gradientField[:, :, :, 0] = g0
        gradientField[:, :, :, 1] = g1
        gradientField[:, :, :, 2] = g2
        maxVariation = 1 + innerTolerance
        innerIter = 0
        maxResidual = 0
        displacement[...] = 0
        maxInnerIter = 50
        while ((maxVariation > innerTolerance) and (innerIter < maxInnerIter)):
            innerIter += 1
            maxVariation = tf.iterateDisplacementField3DCYTHON(
                deltaField, sigmaField, gradientField, lambdaParam,
                totalDisplacement, displacement, residuals)
            opt = np.max(residuals)
            if (maxResidual < opt):
                maxResidual = opt
        maxDisplacement = np.max(np.abs(displacement))
        totalDisplacement, stats = tf.compose_vector_fields3D(
            displacement, totalDisplacement)
        if (maxDisplacement < outerTolerance):
            break
    print "Iter: ", outerIter, "Max lateral displacement:", maxDisplacement, "Max variation:", maxVariation, "Max residual:", maxResidual
    if (previousDisplacement != None):
        return totalDisplacement - previousDisplacement
    return totalDisplacement
Exemple #7
0
def save_registration_results(init_affine, displacement, inverse, params):
    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 = rcommon.getBaseFileName(params.target)
    base_fixed = rcommon.getBaseFileName(params.reference)
    moving = nib.load(params.target).get_data().squeeze().astype(np.float64)
    moving = moving.copy(order='C')
    warped = np.array(tf.warp_volume(moving, displacement)).astype(np.int16)
    img_warped = nib.Nifti1Image(warped, fixed_affine)
    img_warped.to_filename('warpedDiff_'+base_moving+'_'+base_fixed+'.nii.gz')
    #---warp the target image using the affine transformation only---
    moving = nib.load(params.target).get_data().squeeze().astype(np.float64)
    moving = moving.copy(order='C')
    warped = np.array(
        tf.warp_volume_affine(moving, reference_shape, init_affine)
        ).astype(np.int16)
    img_warped = nib.Nifti1Image(warped, fixed_affine)
    img_warped.to_filename('warpedAffine_'+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 = rcommon.getBaseFileName(name)
        warped = np.array(
            tf.warp_discrete_volumeNN(to_warp, displacement)).astype(np.int16)
        img_warped = nib.Nifti1Image(warped, fixed_affine)
        img_warped.to_filename('warpedDiff_'+base_warp+'_'+base_fixed+'.nii.gz')
    #---finally, the optional output
    if params.output_list == None:
        return
    if 'lattice' in params.output_list:
        save_deformed_lattice_3d(
            displacement,
            'latticeDispDiff_'+base_moving+'_'+base_fixed+'.nii.gz')
    if 'inv_lattice' in params.output_list:
        save_deformed_lattice_3d(
            inverse, 'invLatticeDispDiff_'+base_moving+'_'+base_fixed+'.nii.gz')
    if 'displacement' in params.output_list:
        np.save('dispDiff_'+base_moving+'_'+base_fixed+'.npy', displacement)
    if 'inverse' in params.output_list:
        np.save('invDispDiff_'+base_moving+'_'+base_fixed+'.npy', inverse)
Exemple #8
0
def warpNonlinear(targetName, referenceName, dispName, oname, interpolationType='trilinear'):
    baseName=rcommon.getBaseFileName(targetName)
    displacement=np.load(dispName)
    nib_target = nib.load(targetName)
    if interpolationType=='NN':
        target=nib_target.get_data().squeeze().astype(np.int32)
        target=np.copy(target, order='C')
        warped=np.array(tf.warp_discrete_volumeNN(target, displacement))
    else:
        target=nib_target.get_data().squeeze().astype(np.float64)
        target=np.copy(target, order='C')
        warped=np.array(tf.warp_volume(target, displacement))        
    referenceAffine=nib.load(referenceName).get_affine()
    warped=nib.Nifti1Image(warped, referenceAffine)
    if not oname:
        oname="warped"+baseName+"nii.gz"
    warped.to_filename(oname)
def estimateNewMonomodalDiffeomorphicField3D(moving, fixed, lambdaParam, maxOuterIter, previousDisplacement, reportProgress=False):
    '''
    Warning: in the monomodal case, the parameter lambda must be significantly lower than in the multimodal case. Try lambdaParam=1,
    as opposed as lambdaParam=150 used in the multimodal case
    '''
    innerTolerance=1e-3
    outerTolerance=1e-3
    displacement     =np.zeros(shape=(moving.shape)+(3,), dtype=np.float64)
    residuals=np.zeros(shape=(moving.shape), dtype=np.float64)
    gradientField    =np.empty(shape=(moving.shape)+(3,), dtype=np.float64)
    totalDisplacement=np.zeros(shape=(moving.shape)+(3,), dtype=np.float64)
    if(previousDisplacement!=None):
        totalDisplacement[...]=previousDisplacement
    outerIter=0
    while(outerIter<maxOuterIter):
        outerIter+=1
        if(reportProgress):
            print 'Iter:',outerIter,'/',maxOuterIter
        warped=np.array(tf.warp_volume(moving, totalDisplacement))
        sigmaField=np.ones_like(warped, dtype=np.float64)
        deltaField=fixed-warped
        g0, g1, g2=sp.gradient(warped)
        gradientField[:,:,:,0]=g0
        gradientField[:,:,:,1]=g1
        gradientField[:,:,:,2]=g2
        maxVariation=1+innerTolerance
        innerIter=0
        maxResidual=0
        displacement[...]=0
        maxInnerIter=50
        while((maxVariation>innerTolerance)and(innerIter<maxInnerIter)):
            innerIter+=1
            maxVariation=tf.iterateDisplacementField3DCYTHON(deltaField, sigmaField, gradientField,  lambdaParam, totalDisplacement, displacement, residuals)
            opt=np.max(residuals)
            if(maxResidual<opt):
                maxResidual=opt
        maxDisplacement=np.max(np.abs(displacement))
        totalDisplacement, stats=tf.compose_vector_fields3D(displacement, totalDisplacement)
        if(maxDisplacement<outerTolerance):
            break
    print "Iter: ",outerIter, "Max lateral displacement:", maxDisplacement, "Max variation:",maxVariation, "Max residual:", maxResidual
    if(previousDisplacement!=None):
        return totalDisplacement-previousDisplacement
    return totalDisplacement
def saveDeformedLattice3D(dname, oname='deformed_lattice.nii.gz'):
    '''
        saveDeformedLattice3D('displacement_templateT1ToIBSR01T1_diff.npy')
        saveDeformedLattice3D('displacement_templateT1ToIBSR01T1_diffMulti.npy')
    '''
    print 'Loading displacement...'
    displacement=np.load(dname)
    minVal, maxVal=tf.get_displacement_range(displacement, None)
    sh=np.array([np.ceil(maxVal[0]),np.ceil(maxVal[1]),np.ceil(maxVal[2])], dtype=np.int32)
    print sh.dtype
    print sh
    L=np.array(drawLattice3D(sh, 10))
    print 'Warping lattice...'
    warped=np.array(tf.warp_volume(L, displacement, np.eye(4))).astype(np.int16)
    print 'Transforming to Nifti...'
    img=nib.Nifti1Image(warped, np.eye(4))
    print 'Saving warped lattice as:',oname
    img.to_filename(oname)
    print 'done.'
def testEstimateMonomodalDiffeomorphicField3DMultiScale(lambdaParam):
    fnameMoving='data/affineRegistered/templateT1ToIBSR01T1.nii.gz'
    fnameFixed='data/t1/IBSR18/IBSR_01/IBSR_01_ana_strip.nii.gz'
    moving = nib.load(fnameMoving)
    fixed= nib.load(fnameFixed)
    moving=moving.get_data().squeeze().astype(np.float64)
    fixed=fixed.get_data().squeeze().astype(np.float64)
    moving=np.copy(moving, order='C')
    fixed=np.copy(fixed, order='C')
    moving=(moving-moving.min())/(moving.max()-moving.min())
    fixed=(fixed-fixed.min())/(fixed.max()-fixed.min())
    level=3
    #maskMoving=np.ones_like(moving)
    #maskFixed=np.ones_like(fixed)
    movingPyramid=[img for img in rcommon.pyramid_gaussian_3D(moving, level, np.ones_like(moving))]
    fixedPyramid=[img for img in rcommon.pyramid_gaussian_3D(fixed, level, np.ones_like(fixed))]
    rcommon.plotOverlaidPyramids3DCoronal(movingPyramid, fixedPyramid)
    #maxOuterIter=[100,100,100,100,100,100,100,100,100]
    maxOuterIter=[3,3,3,3,3,3,3,3,3]
    #maxOuterIter=[10,20,50,100, 100, 100]
    displacement=estimateMonomodalDiffeomorphicField3DMultiScale(movingPyramid, fixedPyramid, lambdaParam, maxOuterIter, 0,None)
    warped=tf.warp_volume(movingPyramid[0], displacement)
    np.save('displacement_templateT1ToIBSR01T1_diff.npy', displacement)
    np.save('warped_templateT1ToIBSR01T1_diff.npy', warped)
def estimateNewMultimodalDiffeomorphicField3D(moving,
                                              fixed,
                                              initAffine,
                                              lambdaDisplacement,
                                              quantizationLevels,
                                              maxOuterIter,
                                              previousDisplacement,
                                              reportProgress=False):
    innerTolerance = 1e-3
    outerTolerance = 1e-3
    displacement = np.empty(shape=(fixed.shape) + (3, ), dtype=np.float64)
    residuals = np.zeros(shape=(fixed.shape), dtype=np.float64)
    gradientField = np.empty(shape=(fixed.shape) + (3, ), dtype=np.float64)
    totalDisplacement = np.zeros(shape=(fixed.shape) + (3, ), dtype=np.float64)
    if (previousDisplacement != None):
        totalDisplacement[...] = previousDisplacement
    fixedQ = None
    grayLevels = None
    fixedQ, grayLevels, hist = tf.quantizePositiveVolumeCYTHON(
        fixed, quantizationLevels)
    fixedQ = np.array(fixedQ, dtype=np.int32)
    finished = False
    outerIter = 0
    maxDisplacement = None
    maxVariation = None
    maxResidual = 0
    fixedMask = (fixed > 0).astype(np.int32)
    movingMask = (moving > 0).astype(np.int32)
    trustRegion = fixedMask * np.array(
        tf.warp_discrete_volumeNNAffine(
            movingMask, np.array(fixedMask.shape, dtype=np.int32),
            initAffine))  #consider only the overlap after affine registration
    while ((not finished) and (outerIter < maxOuterIter)):
        outerIter += 1
        if (reportProgress):
            print 'Iter:', outerIter, '/', maxOuterIter
            #sys.stdout.flush()
        #---E step---
        #print "Warping..."
        #sys.stdout.flush()
        warped = np.array(tf.warp_volume(moving, totalDisplacement,
                                         initAffine))
        warpedMask = np.array(
            tf.warp_discrete_volumeNN(
                trustRegion, totalDisplacement, np.eye(4))).astype(
                    np.int32)  #the affine mapping was already applied
        #print "Warping NN..."
        #sys.stdout.flush()
        #warpedMovingMask=np.array(tf.warp_volumeNN(movingMask, totalDisplacement)).astype(np.int32)
        #print "Class stats..."
        #sys.stdout.flush()
        means, variances = tf.computeMaskedVolumeClassStatsCYTHON(
            warpedMask, warped, quantizationLevels, fixedQ)
        means[0] = 0
        means = np.array(means)
        variances = np.array(variances)
        sigmaField = variances[fixedQ]
        deltaField = means[
            fixedQ] - warped  #########Delta-field using Arce's rule
        #--M step--
        g0, g1, g2 = sp.gradient(warped)
        gradientField[:, :, :, 0] = g0
        gradientField[:, :, :, 1] = g1
        gradientField[:, :, :, 2] = g2
        maxVariation = 1 + innerTolerance
        innerIter = 0
        maxInnerIter = 100
        displacement[...] = 0
        #print "Iterating..."
        #sys.stdout.flush()
        while ((maxVariation > innerTolerance) and (innerIter < maxInnerIter)):
            innerIter += 1
            maxVariation = tf.iterateDisplacementField3DCYTHON(
                deltaField, sigmaField, gradientField, lambdaDisplacement,
                totalDisplacement, displacement, residuals)
            opt = np.max(residuals)
            if (maxResidual < opt):
                maxResidual = opt
        #--accumulate displacement--
        #print "Exponential3D. Range D:", displacement.min(), displacement.max()
        #sys.stdout.flush()
        expd, inverseNone = tf.vector_field_exponential3D(displacement, False)
        expd = np.array(expd)
        #print "Range expd:", expd.min(), expd.max(), "Range TD:", totalDisplacement.min(), totalDisplacement.max()
        #print "Compose vector fields..."
        #sys.stdout.flush()
        totalDisplacement, stats = tf.compose_vector_fields3D(
            expd, totalDisplacement)
        totalDisplacement = np.array(totalDisplacement)
        #print "Composed rage:", totalDisplacement.min(), totalDisplacement.max()
        #sys.stdout.flush()
        #--check stop condition--
        nrm = np.sqrt(displacement[..., 0]**2 + displacement[..., 1]**2 +
                      displacement[..., 2]**2)
        #maxDisplacement=np.max(nrm)
        maxDisplacement = np.mean(nrm)
        if ((maxDisplacement < outerTolerance) or (outerIter >= maxOuterIter)):
            finished = True
    print "Iter: ", outerIter, "Mean displacement:", maxDisplacement, "Max variation:", maxVariation, "Max residual:", maxResidual
    #sh=fixed.shape
    #rcommon.overlayImages(warped[:,sh[1]//2,:], fixed[:,sh[1]//2,:])
    #rcommon.overlayImages(warped[:,sh[1]//2,:]*warpedMask[:,sh[1]//2,:], fixed[:,sh[1]//2,:])
    #sys.stdout.flush()
    if (previousDisplacement != None):
        #print 'Range TD:', totalDisplacement.min(), totalDisplacement.max(),'. Range PD:', previousDisplacement.min(), previousDisplacement.max()
        #sys.stdout.flush()
        return totalDisplacement - previousDisplacement
    return totalDisplacement
Exemple #13
0
def testEstimateMultimodalSyN3DMultiScale(fnameMoving, fnameFixed, fnameAffine,
                                          warpDir, lambdaParam):
    '''
        testEstimateMultimodalDiffeomorphicField3DMultiScale('IBSR_01_ana_strip.nii.gz', 't1_icbm_normal_1mm_pn0_rf0_peeled.nii.gz', 'IBSR_01_ana_strip_t1_icbm_normal_1mm_pn0_rf0_peeledAffine.txt', 100)
    '''
    print 'Registering', fnameMoving, 'to', fnameFixed, 'with lambda=', lambdaParam
    sys.stdout.flush()
    moving = nib.load(fnameMoving)
    fixed = nib.load(fnameFixed)
    referenceShape = np.array(fixed.shape, dtype=np.int32)
    M = moving.get_affine()
    F = fixed.get_affine()
    if not fnameAffine:
        T = np.eye(4)
    else:
        T = rcommon.readAntsAffine(fnameAffine)
    initAffine = np.linalg.inv(M).dot(T.dot(F))
    print initAffine
    moving = moving.get_data().squeeze().astype(np.float64)
    fixed = fixed.get_data().squeeze().astype(np.float64)
    moving = np.copy(moving, order='C')
    fixed = np.copy(fixed, order='C')
    moving = (moving - moving.min()) / (moving.max() - moving.min())
    fixed = (fixed - fixed.min()) / (fixed.max() - fixed.min())
    level = 2
    maskMoving = moving > 0
    maskFixed = fixed > 0
    movingPyramid = [
        img for img in rcommon.pyramid_gaussian_3D(moving, level, maskMoving)
    ]
    fixedPyramid = [
        img for img in rcommon.pyramid_gaussian_3D(fixed, level, maskFixed)
    ]
    #maxOuterIter=[25,50,100,100, 100, 100]
    maxOuterIter = [2, 2, 2, 2, 2, 2]
    baseMoving = rcommon.getBaseFileName(fnameMoving)
    baseFixed = rcommon.getBaseFileName(fnameFixed)
    #    if(os.path.exists('disp_'+baseMoving+'_'+baseFixed+'.npy')):
    #        displacement=np.load('disp_'+baseMoving+'_'+baseFixed+'.npy')
    #    else:
    displacement, directInverse = estimateMultimodalSyN3DMultiScale(
        movingPyramid, fixedPyramid, initAffine, lambdaParam, maxOuterIter, 0)
    tf.prepend_affine_to_displacement_field(displacement, initAffine)
    #    np.save('disp_'+baseMoving+'_'+baseFixed+'.npy', displacement)
    #####Warp all requested volumes
    #---first the target using tri-linear interpolation---
    moving = nib.load(fnameMoving).get_data().squeeze().astype(np.float64)
    moving = np.copy(moving, order='C')
    warped = np.array(tf.warp_volume(moving, displacement)).astype(np.int16)
    imgWarped = nib.Nifti1Image(warped, F)
    imgWarped.to_filename('warpedDiff_' + baseMoving + '_' + baseFixed +
                          '.nii.gz')
    #---warp using affine only
    moving = nib.load(fnameMoving).get_data().squeeze().astype(np.int32)
    moving = np.copy(moving, order='C')
    warped = np.array(
        tf.warp_discrete_volumeNNAffine(moving, referenceShape,
                                        initAffine)).astype(np.int16)
    imgWarped = nib.Nifti1Image(
        warped, F)  #The affine transformation is the reference's one
    imgWarped.to_filename('warpedAffine_' + baseMoving + '_' + baseFixed +
                          '.nii.gz')
    #---now the rest of the targets using nearest neighbor
    names = [os.path.join(warpDir, name) for name in os.listdir(warpDir)]
    for name in names:
        #---warp using the non-linear deformation
        toWarp = nib.load(name).get_data().squeeze().astype(np.int32)
        toWarp = np.copy(toWarp, order='C')
        baseWarp = rcommon.getBaseFileName(name)
        warped = np.array(tf.warp_discrete_volumeNN(
            toWarp, displacement)).astype(np.int16)
        imgWarped = nib.Nifti1Image(
            warped, F)  #The affine transformation is the reference's one
        imgWarped.to_filename('warpedDiff_' + baseWarp + '_' + baseFixed +
                              '.nii.gz')
        #---warp using affine inly
        warped = np.array(
            tf.warp_discrete_volumeNNAffine(toWarp, referenceShape,
                                            initAffine)).astype(np.int16)
        imgWarped = nib.Nifti1Image(
            warped, F)  #The affine transformation is the reference's one
        imgWarped.to_filename('warpedAffine_' + baseWarp + '_' + baseFixed +
                              '.nii.gz')
    #---finally, the deformed lattices (forward, inverse and resdidual)---
    lambdaParam = 0.9
    maxIter = 100
    tolerance = 1e-4
    print 'Computing inverse...'
    inverse = np.array(
        tf.invert_vector_field3D(displacement, lambdaParam, maxIter,
                                 tolerance))
    residual = np.array(tf.compose_vector_fields3D(displacement, inverse))
    saveDeformedLattice3D(
        displacement,
        'latticeDispDiff_' + baseMoving + '_' + baseFixed + '.nii.gz')
    saveDeformedLattice3D(
        inverse, 'latticeInvDiff_' + baseMoving + '_' + baseFixed + '.nii.gz')
    saveDeformedLattice3D(
        residual, 'latticeResdiff_' + baseMoving + '_' + baseFixed + '.nii.gz')
    residual = np.sqrt(np.sum(residual**2, 3))
    print "Mean residual norm:", residual.mean(), " (", residual.std(
    ), "). Max residual norm:", residual.max()
Exemple #14
0
def estimateNewMultimodalSyNField3D(moving,
                                    fixed,
                                    fWarp,
                                    fInv,
                                    mWarp,
                                    mInv,
                                    initAffine,
                                    lambdaDisplacement,
                                    quantizationLevels,
                                    maxOuterIter,
                                    reportProgress=False):
    '''
        fwWarp: forward warp, the displacement field that warps moving towards fixed
        bwWarp: backward warp, the displacement field that warps fixed towards moving
        initAffine: the affine transformation to bring moving over fixed (this part is not symmetric)
    '''
    print 'Moving shape:', moving.shape, '. Fixed shape:', fixed.shape
    innerTolerance = 1e-3
    outerTolerance = 1e-3
    fixedMask = (fixed > 0).astype(np.int32)
    movingMask = (moving > 0).astype(np.int32)
    if (fWarp != None):
        totalF = fWarp
        totalFInv = fInv
    else:
        totalF = np.zeros(shape=(fixed.shape) + (3, ), dtype=np.float64)
        totalFInv = np.zeros(shape=(fixed.shape) + (3, ), dtype=np.float64)
    if (mWarp != None):
        totalM = mWarp
        totalMInv = mInv
    else:
        totalM = np.zeros(shape=(moving.shape) + (3, ), dtype=np.float64)
        totalMInv = np.zeros(shape=(moving.shape) + (3, ), dtype=np.float64)
    finished = False
    outerIter = 0
    while ((not finished) and (outerIter < maxOuterIter)):
        outerIter += 1
        if (reportProgress):
            print 'Iter:', outerIter, '/', maxOuterIter
        #---E step---
        wmoving = np.array(tf.warp_volume(moving, totalMInv, initAffine))
        wmovingMask = np.array(
            tf.warp_discrete_volumeNN(movingMask, totalMInv,
                                      initAffine)).astype(np.int32)
        wfixed = np.array(tf.warp_volume(fixed, totalFInv))
        wfixedMask = np.array(tf.warp_discrete_volumeNN(
            fixedMask, totalFInv)).astype(np.int32)
        fixedQ, grayLevels, hist = tf.quantizePositiveVolumeCYTHON(
            wfixed, quantizationLevels)
        fixedQ = np.array(fixedQ, dtype=np.int32)
        movingQ, grayLevels, hist = tf.quantizePositiveVolumeCYTHON(
            wmoving, quantizationLevels)
        movingQ = np.array(movingQ, dtype=np.int32)
        trust = wfixedMask * wmovingMask
        meansMoving, variancesMoving = tf.computeMaskedVolumeClassStatsCYTHON(
            trust, wmoving, quantizationLevels, fixedQ)
        meansFixed, variancesFixed = tf.computeMaskedVolumeClassStatsCYTHON(
            trust, wfixed, quantizationLevels, movingQ)
        meansMoving[0] = 0
        meansFixed[0] = 0
        meansMoving = np.array(meansMoving)
        meansFixed = np.array(meansFixed)
        variancesMoving = np.array(variancesMoving)
        sigmaFieldMoving = variancesMoving[fixedQ]
        variancesFixed = np.array(variancesFixed)
        sigmaFieldFixed = variancesFixed[movingQ]
        deltaFieldMoving = meansMoving[fixedQ] - wmoving
        deltaFieldFixed = meansFixed[movingQ] - wfixed
        #--M step--
        movingGradient = np.empty(shape=(moving.shape) + (3, ),
                                  dtype=np.float64)
        movingGradient[:, :, :,
                       0], movingGradient[:, :, :,
                                          1], movingGradient[:, :, :,
                                                             2] = sp.gradient(
                                                                 wmoving)
        #iterate forward field
        maxVariation = 1 + innerTolerance
        innerIter = 0
        maxInnerIter = 100
        fw = np.zeros_like(totalF)
        while ((maxVariation > innerTolerance) and (innerIter < maxInnerIter)):
            innerIter += 1
            maxVariation = tf.iterateDisplacementField3DCYTHON(
                deltaFieldMoving, sigmaFieldMoving, movingGradient,
                lambdaDisplacement, totalF, fw, None)
        del movingGradient
        fw *= 0.5
        totalF = np.array(tf.compose_vector_fields3D(
            fw, totalF))  #Multiply fw by 0.5??
        nrm = np.sqrt(fw[..., 0]**2 + fw[..., 1]**2 + fw[..., 2]**2)
        del fw
        #iterate backward field
        fixedGradient = np.empty(shape=(fixed.shape) + (3, ), dtype=np.float64)
        fixedGradient[:, :, :,
                      0], fixedGradient[:, :, :,
                                        1], fixedGradient[:, :, :,
                                                          2] = sp.gradient(
                                                              wfixed)
        maxVariation = 1 + innerTolerance
        innerIter = 0
        maxInnerIter = 100
        mw = np.zeros_like(totalM)
        while ((maxVariation > innerTolerance) and (innerIter < maxInnerIter)):
            innerIter += 1
            maxVariation = tf.iterateDisplacementField3DCYTHON(
                deltaFieldFixed, sigmaFieldFixed, fixedGradient,
                lambdaDisplacement, totalM, mw, None)
        del fixedGradient
        mw *= 0.5
        totalM = np.array(tf.compose_vector_fields3D(
            mw, totalM))  #Multiply bw by 0.5??
        nrm = np.sqrt(mw[..., 0]**2 + mw[..., 1]**2 + mw[..., 2]**2)
        del mw
        #invert fields
        totalFInv = np.array(
            tf.invert_vector_field_fixed_point3D(totalF, 20, 1e-6))
        totalMInv = np.array(
            tf.invert_vector_field_fixed_point3D(totalM, 20, 1e-6))
        totalF = np.array(
            tf.invert_vector_field_fixed_point3D(totalFInv, 20, 1e-6))
        totalM = np.array(
            tf.invert_vector_field_fixed_point3D(totalMInv, 20, 1e-6))
        maxDisplacement = np.mean(nrm)
        if ((maxDisplacement < outerTolerance) or (outerIter >= maxOuterIter)):
            finished = True
    print "Iter: ", outerIter, "Mean displacement:", maxDisplacement, "Max variation:", maxVariation
    return totalF, totalFInv, totalM, totalMInv
def estimateNewMultimodalDiffeomorphicField3D(moving, fixed, initAffine, lambdaDisplacement, quantizationLevels, maxOuterIter, previousDisplacement, reportProgress=False):
    innerTolerance=1e-3
    outerTolerance=1e-3
    displacement     =np.empty(shape=(fixed.shape)+(3,), dtype=np.float64)
    residuals=np.zeros(shape=(fixed.shape), dtype=np.float64)
    gradientField    =np.empty(shape=(fixed.shape)+(3,), dtype=np.float64)
    totalDisplacement=np.zeros(shape=(fixed.shape)+(3,), dtype=np.float64)
    if(previousDisplacement!=None):
        totalDisplacement[...]=previousDisplacement
    fixedQ=None
    grayLevels=None
    fixedQ, grayLevels, hist=tf.quantizePositiveVolumeCYTHON(fixed, quantizationLevels)
    fixedQ=np.array(fixedQ, dtype=np.int32)
    finished=False
    outerIter=0
    maxDisplacement=None
    maxVariation=None
    maxResidual=0
    fixedMask=(fixed>0).astype(np.int32)
    movingMask=(moving>0).astype(np.int32)
    trustRegion=fixedMask*np.array(tf.warp_discrete_volumeNNAffine(movingMask, np.array(fixedMask.shape, dtype=np.int32), initAffine))#consider only the overlap after affine registration
    while((not finished) and (outerIter<maxOuterIter)):
        outerIter+=1
        if(reportProgress):
            print 'Iter:',outerIter,'/',maxOuterIter
            #sys.stdout.flush()
        #---E step---
        #print "Warping..."
        #sys.stdout.flush()
        warped=np.array(tf.warp_volume(moving, totalDisplacement, initAffine))
        warpedMask=np.array(tf.warp_discrete_volumeNN(trustRegion, totalDisplacement, np.eye(4))).astype(np.int32)#the affine mapping was already applied
        #print "Warping NN..."
        #sys.stdout.flush()
        #warpedMovingMask=np.array(tf.warp_volumeNN(movingMask, totalDisplacement)).astype(np.int32)
        #print "Class stats..."
        #sys.stdout.flush()
        means, variances=tf.computeMaskedVolumeClassStatsCYTHON(warpedMask, warped, quantizationLevels, fixedQ)        
        means[0]=0
        means=np.array(means)
        variances=np.array(variances)
        sigmaField=variances[fixedQ]
        deltaField=means[fixedQ]-warped#########Delta-field using Arce's rule
        #--M step--
        g0, g1, g2=sp.gradient(warped)
        gradientField[:,:,:,0]=g0
        gradientField[:,:,:,1]=g1
        gradientField[:,:,:,2]=g2
        maxVariation=1+innerTolerance
        innerIter=0
        maxInnerIter=100
        displacement[...]=0
        #print "Iterating..."
        #sys.stdout.flush()
        while((maxVariation>innerTolerance)and(innerIter<maxInnerIter)):
            innerIter+=1
            maxVariation=tf.iterateDisplacementField3DCYTHON(deltaField, sigmaField, gradientField,  lambdaDisplacement, totalDisplacement, displacement, residuals)
            opt=np.max(residuals)
            if(maxResidual<opt):
                maxResidual=opt
        #--accumulate displacement--
        #print "Exponential3D. Range D:", displacement.min(), displacement.max()
        #sys.stdout.flush()
        expd, inverseNone=tf.vector_field_exponential3D(displacement, False)
        expd=np.array(expd)
        #print "Range expd:", expd.min(), expd.max(), "Range TD:", totalDisplacement.min(), totalDisplacement.max()
        #print "Compose vector fields..."
        #sys.stdout.flush()
        totalDisplacement, stats=tf.compose_vector_fields3D(expd, totalDisplacement)
        totalDisplacement=np.array(totalDisplacement)
        #print "Composed rage:", totalDisplacement.min(), totalDisplacement.max()
        #sys.stdout.flush()
        #--check stop condition--
        nrm=np.sqrt(displacement[...,0]**2+displacement[...,1]**2+displacement[...,2]**2)
        #maxDisplacement=np.max(nrm)
        maxDisplacement=np.mean(nrm)
        if((maxDisplacement<outerTolerance)or(outerIter>=maxOuterIter)):
            finished=True
    print "Iter: ",outerIter, "Mean displacement:", maxDisplacement, "Max variation:",maxVariation, "Max residual:", maxResidual
    #sh=fixed.shape
    #rcommon.overlayImages(warped[:,sh[1]//2,:], fixed[:,sh[1]//2,:])
    #rcommon.overlayImages(warped[:,sh[1]//2,:]*warpedMask[:,sh[1]//2,:], fixed[:,sh[1]//2,:])
    #sys.stdout.flush()
    if(previousDisplacement!=None):
        #print 'Range TD:', totalDisplacement.min(), totalDisplacement.max(),'. Range PD:', previousDisplacement.min(), previousDisplacement.max()
        #sys.stdout.flush()
        return totalDisplacement-previousDisplacement
    return totalDisplacement
Exemple #16
0
def testEstimateMultimodalSyN3DMultiScale(fnameMoving, fnameFixed, fnameAffine, warpDir, lambdaParam):
    '''
        testEstimateMultimodalDiffeomorphicField3DMultiScale('IBSR_01_ana_strip.nii.gz', 't1_icbm_normal_1mm_pn0_rf0_peeled.nii.gz', 'IBSR_01_ana_strip_t1_icbm_normal_1mm_pn0_rf0_peeledAffine.txt', 100)
    '''
    print 'Registering', fnameMoving, 'to', fnameFixed,'with lambda=',lambdaParam  
    sys.stdout.flush()
    moving = nib.load(fnameMoving)
    fixed= nib.load(fnameFixed)
    referenceShape=np.array(fixed.shape, dtype=np.int32)
    M=moving.get_affine()
    F=fixed.get_affine()
    if not fnameAffine:
        T=np.eye(4)
    else:
        T=rcommon.readAntsAffine(fnameAffine)
    initAffine=np.linalg.inv(M).dot(T.dot(F))
    print initAffine
    moving=moving.get_data().squeeze().astype(np.float64)
    fixed=fixed.get_data().squeeze().astype(np.float64)
    moving=np.copy(moving, order='C')
    fixed=np.copy(fixed, order='C')
    moving=(moving-moving.min())/(moving.max()-moving.min())
    fixed=(fixed-fixed.min())/(fixed.max()-fixed.min())
    level=2
    maskMoving=moving>0
    maskFixed=fixed>0
    movingPyramid=[img for img in rcommon.pyramid_gaussian_3D(moving, level, maskMoving)]
    fixedPyramid=[img for img in rcommon.pyramid_gaussian_3D(fixed, level, maskFixed)]
    #maxOuterIter=[25,50,100,100, 100, 100]
    maxOuterIter=[2,2,2,2,2,2]
    baseMoving=rcommon.getBaseFileName(fnameMoving)
    baseFixed=rcommon.getBaseFileName(fnameFixed)    
#    if(os.path.exists('disp_'+baseMoving+'_'+baseFixed+'.npy')):
#        displacement=np.load('disp_'+baseMoving+'_'+baseFixed+'.npy')
#    else:
    displacement, directInverse=estimateMultimodalSyN3DMultiScale(movingPyramid, fixedPyramid, initAffine, lambdaParam, maxOuterIter, 0)
    tf.prepend_affine_to_displacement_field(displacement, initAffine)
#    np.save('disp_'+baseMoving+'_'+baseFixed+'.npy', displacement)
    #####Warp all requested volumes
    #---first the target using tri-linear interpolation---
    moving=nib.load(fnameMoving).get_data().squeeze().astype(np.float64)
    moving=np.copy(moving, order='C')
    warped=np.array(tf.warp_volume(moving, displacement)).astype(np.int16)
    imgWarped=nib.Nifti1Image(warped, F)
    imgWarped.to_filename('warpedDiff_'+baseMoving+'_'+baseFixed+'.nii.gz')
    #---warp using affine only
    moving=nib.load(fnameMoving).get_data().squeeze().astype(np.int32)
    moving=np.copy(moving, order='C')
    warped=np.array(tf.warp_discrete_volumeNNAffine(moving, referenceShape, initAffine)).astype(np.int16)
    imgWarped=nib.Nifti1Image(warped, F)#The affine transformation is the reference's one
    imgWarped.to_filename('warpedAffine_'+baseMoving+'_'+baseFixed+'.nii.gz')
    #---now the rest of the targets using nearest neighbor
    names=[os.path.join(warpDir,name) for name in os.listdir(warpDir)]
    for name in names:
        #---warp using the non-linear deformation
        toWarp=nib.load(name).get_data().squeeze().astype(np.int32)
        toWarp=np.copy(toWarp, order='C')
        baseWarp=rcommon.getBaseFileName(name)
        warped=np.array(tf.warp_discrete_volumeNN(toWarp, displacement)).astype(np.int16)
        imgWarped=nib.Nifti1Image(warped, F)#The affine transformation is the reference's one
        imgWarped.to_filename('warpedDiff_'+baseWarp+'_'+baseFixed+'.nii.gz')
        #---warp using affine inly
        warped=np.array(tf.warp_discrete_volumeNNAffine(toWarp, referenceShape, initAffine)).astype(np.int16)
        imgWarped=nib.Nifti1Image(warped, F)#The affine transformation is the reference's one
        imgWarped.to_filename('warpedAffine_'+baseWarp+'_'+baseFixed+'.nii.gz')
    #---finally, the deformed lattices (forward, inverse and resdidual)---    
    lambdaParam=0.9
    maxIter=100
    tolerance=1e-4
    print 'Computing inverse...'
    inverse=np.array(tf.invert_vector_field3D(displacement, lambdaParam, maxIter, tolerance))
    residual=np.array(tf.compose_vector_fields3D(displacement, inverse))
    saveDeformedLattice3D(displacement, 'latticeDispDiff_'+baseMoving+'_'+baseFixed+'.nii.gz')
    saveDeformedLattice3D(inverse, 'latticeInvDiff_'+baseMoving+'_'+baseFixed+'.nii.gz')
    saveDeformedLattice3D(residual, 'latticeResdiff_'+baseMoving+'_'+baseFixed+'.nii.gz')
    residual=np.sqrt(np.sum(residual**2,3))
    print "Mean residual norm:", residual.mean()," (",residual.std(), "). Max residual norm:", residual.max()
Exemple #17
0
def estimateNewMultimodalSyNField3D(moving, fixed, fWarp, fInv, mWarp, mInv, initAffine, lambdaDisplacement, quantizationLevels, maxOuterIter, reportProgress=False):
    '''
        fwWarp: forward warp, the displacement field that warps moving towards fixed
        bwWarp: backward warp, the displacement field that warps fixed towards moving
        initAffine: the affine transformation to bring moving over fixed (this part is not symmetric)
    '''
    print 'Moving shape:',moving.shape,'. Fixed shape:',fixed.shape
    innerTolerance=1e-3
    outerTolerance=1e-3
    fixedMask=(fixed>0).astype(np.int32)
    movingMask=(moving>0).astype(np.int32)
    if(fWarp!=None):
        totalF=fWarp
        totalFInv=fInv
    else:
        totalF    =np.zeros(shape=(fixed.shape)+(3,), dtype=np.float64)
        totalFInv =np.zeros(shape=(fixed.shape)+(3,), dtype=np.float64)
    if(mWarp!=None):
        totalM=mWarp
        totalMInv=mInv
    else:
        totalM   =np.zeros(shape=(moving.shape)+(3,), dtype=np.float64)
        totalMInv=np.zeros(shape=(moving.shape)+(3,), dtype=np.float64)
    finished=False
    outerIter=0
    while((not finished) and (outerIter<maxOuterIter)):
        outerIter+=1
        if(reportProgress):
            print 'Iter:',outerIter,'/',maxOuterIter
        #---E step---
        wmoving=np.array(tf.warp_volume(moving, totalMInv, initAffine))
        wmovingMask=np.array(tf.warp_discrete_volumeNN(movingMask, totalMInv, initAffine)).astype(np.int32)
        wfixed=np.array(tf.warp_volume(fixed, totalFInv))
        wfixedMask=np.array(tf.warp_discrete_volumeNN(fixedMask, totalFInv)).astype(np.int32)
        fixedQ, grayLevels, hist=tf.quantizePositiveVolumeCYTHON(wfixed, quantizationLevels)
        fixedQ=np.array(fixedQ, dtype=np.int32)
        movingQ, grayLevels, hist=tf.quantizePositiveVolumeCYTHON(wmoving, quantizationLevels)
        movingQ=np.array(movingQ, dtype=np.int32)
        trust=wfixedMask*wmovingMask
        meansMoving, variancesMoving=tf.computeMaskedVolumeClassStatsCYTHON(trust, wmoving, quantizationLevels, fixedQ)
        meansFixed, variancesFixed=tf.computeMaskedVolumeClassStatsCYTHON(trust, wfixed, quantizationLevels, movingQ)
        meansMoving[0]=0
        meansFixed[0]=0
        meansMoving=np.array(meansMoving)
        meansFixed=np.array(meansFixed)
        variancesMoving=np.array(variancesMoving)
        sigmaFieldMoving=variancesMoving[fixedQ]
        variancesFixed=np.array(variancesFixed)
        sigmaFieldFixed=variancesFixed[movingQ]
        deltaFieldMoving=meansMoving[fixedQ]-wmoving
        deltaFieldFixed=meansFixed[movingQ]-wfixed
        #--M step--
        movingGradient  =np.empty(shape=(moving.shape)+(3,), dtype=np.float64)
        movingGradient[:,:,:,0], movingGradient[:,:,:,1], movingGradient[:,:,:,2]=sp.gradient(wmoving)
        #iterate forward field
        maxVariation=1+innerTolerance
        innerIter=0
        maxInnerIter=100
        fw=np.zeros_like(totalF)
        while((maxVariation>innerTolerance)and(innerIter<maxInnerIter)):
            innerIter+=1
            maxVariation=tf.iterateDisplacementField3DCYTHON(deltaFieldMoving, sigmaFieldMoving, movingGradient,  lambdaDisplacement, totalF, fw, None)
        del movingGradient
        fw*=0.5
        totalF=np.array(tf.compose_vector_fields3D(fw, totalF))#Multiply fw by 0.5??
        nrm=np.sqrt(fw[...,0]**2+fw[...,1]**2+fw[...,2]**2)
        del fw        
        #iterate backward field
        fixedGradient   =np.empty(shape=(fixed.shape)+(3,), dtype=np.float64)
        fixedGradient[:,:,:,0], fixedGradient[:,:,:,1], fixedGradient[:,:,:,2]=sp.gradient(wfixed)
        maxVariation=1+innerTolerance
        innerIter=0
        maxInnerIter=100
        mw=np.zeros_like(totalM)
        while((maxVariation>innerTolerance)and(innerIter<maxInnerIter)):
            innerIter+=1
            maxVariation=tf.iterateDisplacementField3DCYTHON(deltaFieldFixed, sigmaFieldFixed, fixedGradient,  lambdaDisplacement, totalM, mw, None)
        del fixedGradient
        mw*=0.5
        totalM=np.array(tf.compose_vector_fields3D(mw, totalM))#Multiply bw by 0.5??
        nrm=np.sqrt(mw[...,0]**2+mw[...,1]**2+mw[...,2]**2)
        del mw        
        #invert fields
        totalFInv=np.array(tf.invert_vector_field_fixed_point3D(totalF, 20, 1e-6))
        totalMInv=np.array(tf.invert_vector_field_fixed_point3D(totalM, 20, 1e-6))
        totalF=np.array(tf.invert_vector_field_fixed_point3D(totalFInv, 20, 1e-6))
        totalM=np.array(tf.invert_vector_field_fixed_point3D(totalMInv, 20, 1e-6))
        maxDisplacement=np.mean(nrm)
        if((maxDisplacement<outerTolerance)or(outerIter>=maxOuterIter)):
            finished=True
    print "Iter: ",outerIter, "Mean displacement:", maxDisplacement, "Max variation:",maxVariation
    return totalF, totalFInv, totalM, totalMInv