Exemplo n.º 1
0
def warpANTSAffine(targetName, referenceName, affineName, oname, interpolationType='trilinear'):
    baseName=rcommon.getBaseFileName(targetName)
    nib_target=nib.load(targetName)
    nib_reference=nib.load(referenceName)
    M=nib_target.get_affine()
    F=nib_reference.get_affine()
    referenceShape=np.array(nib_reference.shape, dtype=np.int32)
    ######Load and compose affine#####
    if not affineName:
        T=np.eye(4)
    else:
        T=rcommon.readAntsAffine(affineName)
    affineComposition=np.linalg.inv(M).dot(T.dot(F))
    ######################
    if interpolationType=='NN':
        target=nib_target.get_data().squeeze().astype(np.int32)
        target=np.copy(target, order='C')
        warped=np.array(tf.warp_discrete_volumeNNAffine(target, referenceShape, affineComposition)).astype(np.int16)
    else:
        target=nib_target.get_data().squeeze().astype(np.float64)
        target=np.copy(target, order='C')
        warped=np.array(tf.warp_volume_affine(target, referenceShape, affineComposition)).astype(np.int16)
    warped=nib.Nifti1Image(warped, F)
    if not oname:
        oname="warped"+baseName+"nii.gz"
    warped.to_filename(oname)
Exemplo n.º 2
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()
Exemplo n.º 3
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()
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
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