def testInversion_invertible(): displacement_clean=tf.create_invertible_displacement_field(256, 256, 0.5, 8) detJacobian=rcommon.computeJacobianField(displacement_clean) plt.figure() plt.imshow(detJacobian) print 'Range:', detJacobian.min(), detJacobian.max() X1,X0=np.mgrid[0:displacement_clean.shape[0], 0:displacement_clean.shape[1]] CS=plt.contour(X0,X1,detJacobian,levels=[0.0], colors='b') plt.clabel(CS, inline=1, fontsize=10) plt.title('det(J(displacement))') displacement=displacement_clean+np.random.normal(0.0, 1.1, displacement_clean.shape) #displacement=np.array(displacement_clean) #inverse=rcommon.invert_vector_field_fixed_point(displacement, 100, 1e-7) #inverse=np.array(tf.invert_vector_field(displacement, 0.1, 100, 1e-7)) lambdaParam=5.0 #########Jacobi########## inverse=np.array(tf.invert_vector_field(displacement, lambdaParam, 100, 1e-6)) residual, stats=tf.compose_vector_fields(displacement_clean, inverse) residual=np.array(residual) print 'Jacobi. Max:',stats[0], '. Mean:',stats[1],'Std:',stats[2] [d,invd,res, detJ]=rcommon.plotDiffeomorphism(displacement, inverse, residual, 'Jacobi', 7) #########Fixed point###### inverse=np.array(tf.invert_vector_field_fixed_point(displacement, 100, 1e-6)) residual, stats=tf.compose_vector_fields(displacement_clean, inverse) residual=np.array(residual) print 'Fixed point. Max:',stats[0], '. Mean:',stats[1],'Std:',stats[2] [d,invd,res, detJ]=rcommon.plotDiffeomorphism(displacement, inverse, residual, 'Fixed point', 7) #########TV-L2########### inverse=np.array(tf.invert_vector_field_tv_l2(displacement, lambdaParam, 3000, 1e-6)) residual, stats=tf.compose_vector_fields(displacement_clean, inverse) residual=np.array(residual) print 'TV-L2. Max:',stats[0], '. Mean:',stats[1],'Std:',stats[2] [d,invd,res, detJ]=rcommon.plotDiffeomorphism(displacement, inverse, residual, 'TV-L2', 7)
def estimateMonomodalSyNField2DMultiScale(movingPyramid, fixedPyramid, lambdaParam, maxOuterIter, level, displacementList): n = len(movingPyramid) if (level == (n - 1)): totalF, totalFInv, totalM, totalMInv = estimateNewMonomodalSyNField2D( movingPyramid[level], fixedPyramid[level], None, None, None, None, lambdaParam, maxOuterIter[level]) if (displacementList != None): displacementList.insert(0, totalM) return totalF, totalFInv, totalM, totalMInv subF, subFInv, subM, subMInv = estimateMonomodalSyNField2DMultiScale( movingPyramid, fixedPyramid, lambdaParam, maxOuterIter, level + 1, displacementList) sh = np.array(fixedPyramid[level].shape).astype(np.int32) upF = np.array(tf.upsample_displacement_field(subF, sh)) * 2 upFInv = np.array(tf.upsample_displacement_field(subFInv, sh)) * 2 upM = np.array(tf.upsample_displacement_field(subM, sh)) * 2 upMInv = np.array(tf.upsample_displacement_field(subMInv, sh)) * 2 totalF, totalFInv, totalM, totalMInv = estimateNewMonomodalSyNField2D( movingPyramid[level], fixedPyramid[level], upF, upFInv, upM, upMInv, lambdaParam, maxOuterIter[level]) if (displacementList != None): displacementList.insert(0, totalM) if (level == 0): totalF = np.array(tf.compose_vector_fields(totalF, totalMInv)) totalM = np.array(tf.compose_vector_fields(totalM, totalFInv)) return totalM, totalF return totalF, totalFInv, totalM, totalMInv
def testCircleToCMonomodalDiffeomorphic(lambdaParam): import numpy as np import tensorFieldUtils as tf import matplotlib.pyplot as plt import registrationCommon as rcommon fname0='data/circle.png' #fname0='data/C_trans.png' fname1='data/C.png' circleToCDisplacementName='circleToCDisplacement.npy' circleToCDisplacementInverseName='circleToCDisplacementInverse.npy' nib_moving=plt.imread(fname0) nib_fixed=plt.imread(fname1) moving=nib_moving[:,:,0] fixed=nib_fixed[:,:,1] moving=(moving-moving.min())/(moving.max() - moving.min()) fixed=(fixed-fixed.min())/(fixed.max() - fixed.min()) level=3 maskMoving=moving>0 maskFixed=fixed>0 movingPyramid=[img for img in rcommon.pyramid_gaussian_2D(moving, level, np.ones_like(maskMoving))] fixedPyramid=[img for img in rcommon.pyramid_gaussian_2D(fixed, level, np.ones_like(maskFixed))] rcommon.plotOverlaidPyramids(movingPyramid, fixedPyramid) displacementList=[] maxOuterIter=[10,50,100,100,100,100,100,100,100] if(os.path.exists(circleToCDisplacementName)): displacement=np.load(circleToCDisplacementName) inverse=np.load(circleToCDisplacementInverseName) else: displacement, inverse=estimateMonomodalDiffeomorphicField2DMultiScale(movingPyramid, fixedPyramid, lambdaParam, maxOuterIter, 0,displacementList) np.save(circleToCDisplacementName, displacement) np.save(circleToCDisplacementInverseName, inverse) X1,X0=np.mgrid[0:displacement.shape[0], 0:displacement.shape[1]] detJacobian=rcommon.computeJacobianField(displacement) plt.figure() plt.imshow(detJacobian) CS=plt.contour(X0,X1,detJacobian,levels=[0.0], colors='b') plt.clabel(CS, inline=1, fontsize=10) plt.title('det(J(displacement))') print 'J range:', '[', detJacobian.min(), detJacobian.max(),']' #directInverse=np.array(tf.invert_vector_field(displacement, 0.5, 1000, 1e-7)) directInverse=np.array(tf.invert_vector_field_fixed_point(displacement, 100, 1e-7)) detJacobianInverse=rcommon.computeJacobianField(directInverse) plt.figure() plt.imshow(detJacobianInverse) CS=plt.contour(X0,X1,detJacobianInverse, levels=[0.0],colors='w') plt.clabel(CS, inline=1, fontsize=10) plt.title('det(J(displacement^-1))') print 'J^-1 range:', '[', detJacobianInverse.min(), detJacobianInverse.max(),']' #directInverse=rcommon.invert_vector_field_fixed_point(displacement, 1000, 1e-7) residual, stats=tf.compose_vector_fields(displacement, inverse) residual=np.array(residual) directResidual,stats=tf.compose_vector_fields(displacement, directInverse) directResidual=np.array(directResidual) # warpPyramid=[rcommon.warpImage(movingPyramid[i], displacementList[i]) for i in range(level+1)] # rcommon.plotOverlaidPyramids(warpPyramid, fixedPyramid) # rcommon.overlayImages(warpPyramid[0], fixedPyramid[0]) rcommon.plotDiffeomorphism(displacement, inverse, residual, 'inv-joint', 7) rcommon.plotDiffeomorphism(displacement, directInverse, directResidual, 'inv-direct', 7) tf.write_double_buffer(displacement.reshape(-1), 'displacement.bin')
def estimateNewMonomodalDiffeomorphicField2D(moving, fixed, lambdaParam, maxOuterIter, previousDisplacement, previousDisplacementInverse): ''' 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-4 displacement = np.zeros(shape=(moving.shape) + (2, ), dtype=np.float64) gradientField = np.empty(shape=(moving.shape) + (2, ), dtype=np.float64) totalDisplacement = np.zeros(shape=(moving.shape) + (2, ), dtype=np.float64) totalDisplacementInverse = np.zeros(shape=(moving.shape) + (2, ), dtype=np.float64) if (previousDisplacement != None): totalDisplacement[...] = previousDisplacement totalDisplacementInverse[...] = previousDisplacementInverse outerIter = 0 framesToCapture = 5 maxOuterIter = framesToCapture * ( (maxOuterIter + framesToCapture - 1) / framesToCapture) itersPerCapture = maxOuterIter / framesToCapture plt.figure() while (outerIter < maxOuterIter): outerIter += 1 print 'Outer iter:', outerIter warped = np.array(tf.warp_image(moving, totalDisplacement, None)) if ((outerIter == 1) or (outerIter % itersPerCapture == 0)): plt.subplot(1, framesToCapture + 1, 1 + outerIter / itersPerCapture) rcommon.overlayImages(warped, fixed, False) plt.title('Iter:' + str(outerIter - 1)) sigmaField = np.ones_like(warped, dtype=np.float64) deltaField = fixed - warped gradientField[:, :, 0], gradientField[:, :, 1] = sp.gradient(warped) maxVariation = 1 + innerTolerance innerIter = 0 displacement[...] = 0 maxInnerIter = 200 while ((maxVariation > innerTolerance) and (innerIter < maxInnerIter)): innerIter += 1 maxVariation = tf.iterateDisplacementField2DCYTHON( deltaField, sigmaField, gradientField, lambdaParam, displacement, None) #maxDisplacement=np.max(np.abs(displacement)) expd, invexpd = tf.vector_field_exponential(displacement, True) totalDisplacement, stats = tf.compose_vector_fields( displacement, totalDisplacement) #totalDisplacement=np.array(totalDisplacement) totalDisplacementInverse, stats = tf.compose_vector_fields( totalDisplacementInverse, invexpd) #totalDisplacementInverse=np.array(totalDisplacementInverse) #if(maxDisplacement<outerTolerance): #break print "Iter: ", innerIter, "Max variation:", maxVariation return totalDisplacement, totalDisplacementInverse
def testEstimateMonomodalDiffeomorphicField2DMultiScale(lambdaParam): fname0='IBSR_01_to_02.nii.gz' fname1='data/t1/IBSR18/IBSR_02/IBSR_02_ana_strip.nii.gz' nib_moving = nib.load(fname0) nib_fixed= nib.load(fname1) moving=nib_moving.get_data().squeeze().astype(np.float64) fixed=nib_fixed.get_data().squeeze().astype(np.float64) moving=np.copy(moving, order='C') fixed=np.copy(fixed, order='C') sl=moving.shape sr=fixed.shape level=5 #---sagital--- moving=moving[sl[0]//2,:,:].copy() fixed=fixed[sr[0]//2,:,:].copy() #---coronal--- #moving=moving[:,sl[1]//2,:].copy() #fixed=fixed[:,sr[1]//2,:].copy() #---axial--- #moving=moving[:,:,sl[2]//2].copy() #fixed=fixed[:,:,sr[2]//2].copy() maskMoving=moving>0 maskFixed=fixed>0 movingPyramid=[img for img in rcommon.pyramid_gaussian_2D(moving, level, maskMoving)] fixedPyramid=[img for img in rcommon.pyramid_gaussian_2D(fixed, level, maskFixed)] rcommon.plotOverlaidPyramids(movingPyramid, fixedPyramid) displacementList=[] maxIter=200 displacement, inverse=estimateMonomodalDiffeomorphicField2DMultiScale(movingPyramid, fixedPyramid, lambdaParam, maxIter, 0,displacementList) residual=tf.compose_vector_fields(displacement, inverse) warpPyramid=[rcommon.warpImage(movingPyramid[i], displacementList[i]) for i in range(level+1)] rcommon.plotOverlaidPyramids(warpPyramid, fixedPyramid) rcommon.overlayImages(warpPyramid[0], fixedPyramid[0]) rcommon.plotDiffeomorphism(displacement, inverse, residual)
def testCircleToCMonomodalSyNEM(lambdaParam, maxOuterIter): fname0='data/circle.png' #fname0='data/C_trans.png' fname1='data/C.png' nib_moving=plt.imread(fname0) nib_fixed=plt.imread(fname1) moving=nib_moving[:,:,0] fixed=nib_fixed[:,:,1] moving=(moving-moving.min())/(moving.max() - moving.min()) fixed=(fixed-fixed.min())/(fixed.max() - fixed.min()) level=3 maskMoving=moving>0 maskFixed=fixed>0 movingPyramid=[img for img in rcommon.pyramid_gaussian_2D(moving, level, maskMoving)] fixedPyramid=[img for img in rcommon.pyramid_gaussian_2D(fixed, level, maskFixed)] rcommon.plotOverlaidPyramids(movingPyramid, fixedPyramid) displacementList=[] displacement, dinv=estimateMonomodalSyNField2DMultiScale(movingPyramid, fixedPyramid, lambdaParam, maxOuterIter, 0,displacementList) inverse=np.array(tf.invert_vector_field(displacement, 0.75, 300, 1e-7)) residual, stats=tf.compose_vector_fields(displacement, inverse) residual=np.array(residual) warpPyramid=[rcommon.warpImage(movingPyramid[i], displacementList[i]) for i in range(level+1)] rcommon.plotOverlaidPyramids(warpPyramid, fixedPyramid) rcommon.overlayImages(warpPyramid[0], fixedPyramid[0]) rcommon.plotDiffeomorphism(displacement, inverse, residual, '',7)
def testCircleToCMonomodalSyNEM(lambdaParam, maxOuterIter): fname0 = 'data/circle.png' #fname0='data/C_trans.png' fname1 = 'data/C.png' nib_moving = plt.imread(fname0) nib_fixed = plt.imread(fname1) moving = nib_moving[:, :, 0] fixed = nib_fixed[:, :, 1] moving = (moving - moving.min()) / (moving.max() - moving.min()) fixed = (fixed - fixed.min()) / (fixed.max() - fixed.min()) level = 3 maskMoving = moving > 0 maskFixed = fixed > 0 movingPyramid = [ img for img in rcommon.pyramid_gaussian_2D(moving, level, maskMoving) ] fixedPyramid = [ img for img in rcommon.pyramid_gaussian_2D(fixed, level, maskFixed) ] rcommon.plotOverlaidPyramids(movingPyramid, fixedPyramid) displacementList = [] displacement, dinv = estimateMonomodalSyNField2DMultiScale( movingPyramid, fixedPyramid, lambdaParam, maxOuterIter, 0, displacementList) inverse = np.array(tf.invert_vector_field(displacement, 0.75, 300, 1e-7)) residual, stats = tf.compose_vector_fields(displacement, inverse) residual = np.array(residual) warpPyramid = [ rcommon.warpImage(movingPyramid[i], displacementList[i]) for i in range(level + 1) ] rcommon.plotOverlaidPyramids(warpPyramid, fixedPyramid) rcommon.overlayImages(warpPyramid[0], fixedPyramid[0]) rcommon.plotDiffeomorphism(displacement, inverse, residual, '', 7)
def testInversion(lambdaParam): fname0='data/circle.png' fname1='data/C.png' circleToCDisplacementName='circleToCDisplacement.npy' circleToCDisplacementInverseName='circleToCDisplacementInverse.npy' nib_moving=plt.imread(fname0) nib_fixed=plt.imread(fname1) moving=nib_moving[:,:,0] fixed=nib_fixed[:,:,1] moving=(moving-moving.min())/(moving.max() - moving.min()) fixed=(fixed-fixed.min())/(fixed.max() - fixed.min()) level=3 maskMoving=moving>0 maskFixed=fixed>0 movingPyramid=[img for img in rcommon.pyramid_gaussian_2D(moving, level, np.ones_like(maskMoving))] fixedPyramid=[img for img in rcommon.pyramid_gaussian_2D(fixed, level, np.ones_like(maskFixed))] rcommon.plotOverlaidPyramids(movingPyramid, fixedPyramid) displacementList=[] maxOuterIter=[10,50,100,100,100,100,100,100,100] if(os.path.exists(circleToCDisplacementName)): displacement=np.load(circleToCDisplacementName) inverse=np.load(circleToCDisplacementInverseName) else: displacement, inverse=estimateMonomodalDiffeomorphicField2DMultiScale(movingPyramid, fixedPyramid, lambdaParam, maxOuterIter, 0,displacementList) np.save(circleToCDisplacementName, displacement) np.save(circleToCDisplacementInverseName, inverse) print 'vector field exponential' expd, invexpd=tf.vector_field_exponential(displacement, True) print 'vector field inversion' directInverse=tf.invert_vector_field(displacement, 1.0, 10000, 1e-7) print 'vector field inversion' directExpInverse=tf.invert_vector_field(expd, 1.0, 10000, 1e-7) ###Now compare inversions### residualJoint=np.array(tf.compose_vector_fields(displacement, inverse)[0]) residualDirect=np.array(tf.compose_vector_fields(displacement, directInverse)[0]) residualExpJoint=np.array(tf.compose_vector_fields(expd, invexpd)[0]) residualExpDirect=np.array(tf.compose_vector_fields(expd, directExpInverse)[0]) rcommon.plotDiffeomorphism(displacement, inverse, residualJoint, 'D-joint') rcommon.plotDiffeomorphism(expd, invexpd, residualExpJoint, 'expD-joint') d,invd,res,jacobian=rcommon.plotDiffeomorphism(displacement, directInverse, residualDirect, 'D-direct') rcommon.plotDiffeomorphism(expd, directExpInverse, residualExpDirect, 'expD-direct') sp.misc.imsave('circleToC_deformation.png', d) sp.misc.imsave('circleToC_inverse_deformation.png', invd) sp.misc.imsave('circleToC_residual_deformation.png', res) tf.write_double_buffer(np.array(displacement).reshape(-1), '../inverse/experiments/displacement.bin') tf.write_double_buffer(np.array(displacement).reshape(-1), '../inverse/experiments/displacement_clean.bin')
def estimateNewMonomodalDiffeomorphicField2D(moving, fixed, lambdaParam, maxOuterIter, previousDisplacement, previousDisplacementInverse): ''' 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-4 displacement =np.zeros(shape=(moving.shape)+(2,), dtype=np.float64) gradientField =np.empty(shape=(moving.shape)+(2,), dtype=np.float64) totalDisplacement=np.zeros(shape=(moving.shape)+(2,), dtype=np.float64) totalDisplacementInverse=np.zeros(shape=(moving.shape)+(2,), dtype=np.float64) if(previousDisplacement!=None): totalDisplacement[...]=previousDisplacement totalDisplacementInverse[...]=previousDisplacementInverse outerIter=0 framesToCapture=5 maxOuterIter=framesToCapture*((maxOuterIter+framesToCapture-1)/framesToCapture) itersPerCapture=maxOuterIter/framesToCapture plt.figure() while(outerIter<maxOuterIter): outerIter+=1 print 'Outer iter:', outerIter warped=np.array(tf.warp_image(moving, totalDisplacement, None)) if((outerIter==1) or (outerIter%itersPerCapture==0)): plt.subplot(1,framesToCapture+1, 1+outerIter/itersPerCapture) rcommon.overlayImages(warped, fixed, False) plt.title('Iter:'+str(outerIter-1)) sigmaField=np.ones_like(warped, dtype=np.float64) deltaField=fixed-warped gradientField[:,:,0], gradientField[:,:,1]=sp.gradient(warped) maxVariation=1+innerTolerance innerIter=0 displacement[...]=0 maxInnerIter=200 while((maxVariation>innerTolerance)and(innerIter<maxInnerIter)): innerIter+=1 maxVariation=tf.iterateDisplacementField2DCYTHON(deltaField, sigmaField, gradientField, lambdaParam, displacement, None) #maxDisplacement=np.max(np.abs(displacement)) expd, invexpd=tf.vector_field_exponential(displacement, True) totalDisplacement, stats=tf.compose_vector_fields(displacement, totalDisplacement) #totalDisplacement=np.array(totalDisplacement) totalDisplacementInverse, stats=tf.compose_vector_fields(totalDisplacementInverse, invexpd) #totalDisplacementInverse=np.array(totalDisplacementInverse) #if(maxDisplacement<outerTolerance): #break print "Iter: ",innerIter, "Max variation:",maxVariation return totalDisplacement, totalDisplacementInverse
def testInversion_invertible(): displacement_clean = tf.create_invertible_displacement_field( 256, 256, 0.5, 8) detJacobian = rcommon.computeJacobianField(displacement_clean) plt.figure() plt.imshow(detJacobian) print 'Range:', detJacobian.min(), detJacobian.max() X1, X0 = np.mgrid[0:displacement_clean.shape[0], 0:displacement_clean.shape[1]] CS = plt.contour(X0, X1, detJacobian, levels=[0.0], colors='b') plt.clabel(CS, inline=1, fontsize=10) plt.title('det(J(displacement))') displacement = displacement_clean + np.random.normal( 0.0, 1.1, displacement_clean.shape) #displacement=np.array(displacement_clean) #inverse=rcommon.invert_vector_field_fixed_point(displacement, 100, 1e-7) #inverse=np.array(tf.invert_vector_field(displacement, 0.1, 100, 1e-7)) lambdaParam = 5.0 #########Jacobi########## inverse = np.array( tf.invert_vector_field(displacement, lambdaParam, 100, 1e-6)) residual, stats = tf.compose_vector_fields(displacement_clean, inverse) residual = np.array(residual) print 'Jacobi. Max:', stats[0], '. Mean:', stats[1], 'Std:', stats[2] [d, invd, res, detJ] = rcommon.plotDiffeomorphism(displacement, inverse, residual, 'Jacobi', 7) #########Fixed point###### inverse = np.array( tf.invert_vector_field_fixed_point(displacement, 100, 1e-6)) residual, stats = tf.compose_vector_fields(displacement_clean, inverse) residual = np.array(residual) print 'Fixed point. Max:', stats[0], '. Mean:', stats[1], 'Std:', stats[2] [d, invd, res, detJ] = rcommon.plotDiffeomorphism(displacement, inverse, residual, 'Fixed point', 7) #########TV-L2########### inverse = np.array( tf.invert_vector_field_tv_l2(displacement, lambdaParam, 3000, 1e-6)) residual, stats = tf.compose_vector_fields(displacement_clean, inverse) residual = np.array(residual) print 'TV-L2. Max:', stats[0], '. Mean:', stats[1], 'Std:', stats[2] [d, invd, res, detJ] = rcommon.plotDiffeomorphism(displacement, inverse, residual, 'TV-L2', 7)
def update(new_displacement, current_displacement): dim = len(new_displacement.shape)-1 mse = np.sqrt(np.sum((current_displacement**2), -1)).mean() if dim == 2: updated, stats = tf.compose_vector_fields(new_displacement, current_displacement) else: updated, stats = tf.compose_vector_fields3D(new_displacement, current_displacement) return np.array(updated), np.array(mse)
def estimateMonomodalSyNField2DMultiScale(movingPyramid, fixedPyramid, lambdaParam, maxOuterIter, level, displacementList): n=len(movingPyramid) if(level==(n-1)): totalF, totalFInv, totalM, totalMInv=estimateNewMonomodalSyNField2D(movingPyramid[level], fixedPyramid[level], None, None, None, None, lambdaParam, maxOuterIter[level]) if(displacementList!=None): displacementList.insert(0,totalM) return totalF, totalFInv, totalM, totalMInv subF, subFInv, subM, subMInv=estimateMonomodalSyNField2DMultiScale(movingPyramid, fixedPyramid, lambdaParam, maxOuterIter, level+1, displacementList) sh=np.array(fixedPyramid[level].shape).astype(np.int32) upF=np.array(tf.upsample_displacement_field(subF, sh))*2 upFInv=np.array(tf.upsample_displacement_field(subFInv, sh))*2 upM=np.array(tf.upsample_displacement_field(subM, sh))*2 upMInv=np.array(tf.upsample_displacement_field(subMInv, sh))*2 totalF, totalFInv, totalM, totalMInv=estimateNewMonomodalSyNField2D(movingPyramid[level], fixedPyramid[level], upF, upFInv, upM, upMInv, lambdaParam, maxOuterIter[level]) if(displacementList!=None): displacementList.insert(0, totalM) if(level==0): totalF=np.array(tf.compose_vector_fields(totalF, totalMInv)) totalM=np.array(tf.compose_vector_fields(totalM, totalFInv)) return totalM, totalF return totalF, totalFInv, totalM, totalMInv
def compute_inversion_error(self): r''' Returns the inversion error of the displacement fields TO-DO: the inversion error should take into account the affine transformations as well. ''' if self.dim == 2: residual, stats = tf.compose_vector_fields(self.forward, self.backward) else: residual, stats = tf.compose_vector_fields3D(self.forward, self.backward) return residual, stats
def compose(self, applyFirst): r''' Computes the composition G(F(.)) where G is this transformation and F is the transformation given as parameter ''' B=applyFirst.affine_post C=self.affine_pre if B==None: affine_prod=C elif C==None: affine_prod=B else: affine_prod=C.dot(B) if affine_prod!=None: affine_prod_inv=linalg.inv(affine_prod).copy(order='C') else: affine_prod_inv=None if self.dim == 2: forward=applyFirst.forward.copy() tf.append_affine_to_displacement_field_2d(forward, affine_prod) forward, stats = tf.compose_vector_fields(forward, self.forward) backward=self.backward.copy() tf.append_affine_to_displacement_field_2d(backward, affine_prod_inv) backward, stats = tf.compose_vector_fields(backward, applyFirst.backward) else: forward=applyFirst.forward.copy() tf.append_affine_to_displacement_field_3d(forward, affine_prod) forward, stats = tf.compose_vector_fields3D(forward, self.forward) backward=self.backward.copy() tf.append_affine_to_displacement_field_3d(backward, affine_prod_inv) backward, stats = tf.compose_vector_fields3D(backward, applyFirst.backward) composition=TransformationModel(forward, backward, applyFirst.affine_pre, self.affine_post) return composition
def test_optimizer_monomodal_2d(): r''' Classical Circle-To-C experiment for 2D Monomodal registration ''' fname_moving = 'data/circle.png' fname_fixed = 'data/C.png' moving = plt.imread(fname_moving) fixed = plt.imread(fname_fixed) moving = moving[:, :, 0].astype(np.float64) fixed = fixed[:, :, 0].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()) ################Configure and run the Optimizer##################### max_iter = [i for i in [20, 100, 100, 100]] similarity_metric = SSDMetric(2, { 'symmetric': True, 'lambda': 5.0, 'stepType': SSDMetric.GAUSS_SEIDEL_STEP }) optimizer_parameters = { 'max_iter': max_iter, 'inversion_iter': 40, 'inversion_tolerance': 1e-3, 'report_status': True } update_rule = UpdateRule.Composition() registration_optimizer = SymmetricRegistrationOptimizer( fixed, moving, None, None, similarity_metric, update_rule, optimizer_parameters) registration_optimizer.optimize() #######################show results################################# displacement = registration_optimizer.get_forward() direct_inverse = registration_optimizer.get_backward() moving_to_fixed = np.array(tf.warp_image(moving, displacement)) fixed_to_moving = np.array(tf.warp_image(fixed, direct_inverse)) rcommon.overlayImages(moving_to_fixed, fixed, True) rcommon.overlayImages(fixed_to_moving, moving, True) direct_residual, stats = tf.compose_vector_fields(displacement, direct_inverse) direct_residual = np.array(direct_residual) rcommon.plotDiffeomorphism(displacement, direct_inverse, direct_residual, 'inv-direct', 7)
def test_optimizer_monomodal_2d(): r''' Classical Circle-To-C experiment for 2D Monomodal registration ''' fname_moving = 'data/circle.png' fname_fixed = 'data/C.png' moving = plt.imread(fname_moving) fixed = plt.imread(fname_fixed) moving = moving[:, :, 0].astype(np.float64) fixed = fixed[:, :, 0].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()) ################Configure and run the Optimizer##################### max_iter = [i for i in [20, 100, 100, 100]] similarity_metric = SSDMetric(2, {'symmetric':True, 'lambda':5.0, 'stepType':SSDMetric.GAUSS_SEIDEL_STEP}) optimizer_parameters = { 'max_iter':max_iter, 'inversion_iter':40, 'inversion_tolerance':1e-3, 'report_status':True} update_rule = UpdateRule.Composition() registration_optimizer = SymmetricRegistrationOptimizer(fixed, moving, None, None, similarity_metric, update_rule, optimizer_parameters) registration_optimizer.optimize() #######################show results################################# displacement = registration_optimizer.get_forward() direct_inverse = registration_optimizer.get_backward() moving_to_fixed = np.array(tf.warp_image(moving, displacement)) fixed_to_moving = np.array(tf.warp_image(fixed, direct_inverse)) rcommon.overlayImages(moving_to_fixed, fixed, True) rcommon.overlayImages(fixed_to_moving, moving, True) direct_residual, stats = tf.compose_vector_fields(displacement, direct_inverse) direct_residual = np.array(direct_residual) rcommon.plotDiffeomorphism(displacement, direct_inverse, direct_residual, 'inv-direct', 7)
def testEstimateMonomodalDiffeomorphicField2DMultiScale(lambdaParam): fname0 = 'IBSR_01_to_02.nii.gz' fname1 = 'data/t1/IBSR18/IBSR_02/IBSR_02_ana_strip.nii.gz' nib_moving = nib.load(fname0) nib_fixed = nib.load(fname1) moving = nib_moving.get_data().squeeze().astype(np.float64) fixed = nib_fixed.get_data().squeeze().astype(np.float64) moving = np.copy(moving, order='C') fixed = np.copy(fixed, order='C') sl = moving.shape sr = fixed.shape level = 5 #---sagital--- moving = moving[sl[0] // 2, :, :].copy() fixed = fixed[sr[0] // 2, :, :].copy() #---coronal--- #moving=moving[:,sl[1]//2,:].copy() #fixed=fixed[:,sr[1]//2,:].copy() #---axial--- #moving=moving[:,:,sl[2]//2].copy() #fixed=fixed[:,:,sr[2]//2].copy() maskMoving = moving > 0 maskFixed = fixed > 0 movingPyramid = [ img for img in rcommon.pyramid_gaussian_2D(moving, level, maskMoving) ] fixedPyramid = [ img for img in rcommon.pyramid_gaussian_2D(fixed, level, maskFixed) ] rcommon.plotOverlaidPyramids(movingPyramid, fixedPyramid) displacementList = [] maxIter = 200 displacement, inverse = estimateMonomodalDiffeomorphicField2DMultiScale( movingPyramid, fixedPyramid, lambdaParam, maxIter, 0, displacementList) residual = tf.compose_vector_fields(displacement, inverse) warpPyramid = [ rcommon.warpImage(movingPyramid[i], displacementList[i]) for i in range(level + 1) ] rcommon.plotOverlaidPyramids(warpPyramid, fixedPyramid) rcommon.overlayImages(warpPyramid[0], fixedPyramid[0]) rcommon.plotDiffeomorphism(displacement, inverse, residual)
def test_optimizer_monomodal_2d(): r""" Classical Circle-To-C experiment for 2D Monomodal registration """ fname_moving = "data/circle.png" fname_fixed = "data/C.png" nib_moving = plt.imread(fname_moving) nib_fixed = plt.imread(fname_fixed) moving = nib_moving[:, :, 0].astype(np.float64) fixed = nib_fixed[:, :, 1].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()) ################Configure and run the Optimizer##################### max_iter = [i for i in [25, 100, 100, 100]] similarity_metric = SSDMetric({"lambda": 5.0, "max_inner_iter": 50, "step_type": SSDMetric.GAUSS_SEIDEL_STEP}) update_rule = UpdateRule.Composition() optimizer_parameters = { "max_iter": max_iter, "inversion_iter": 40, "inversion_tolerance": 1e-3, "report_status": True, } registration_optimizer = AsymmetricRegistrationOptimizer( fixed, moving, None, None, similarity_metric, update_rule, optimizer_parameters ) registration_optimizer.optimize() #######################show results################################# displacement = registration_optimizer.get_forward() direct_inverse = registration_optimizer.get_backward() moving_to_fixed = np.array(tf.warp_image(moving, displacement)) fixed_to_moving = np.array(tf.warp_image(fixed, direct_inverse)) rcommon.overlayImages(moving_to_fixed, fixed, True) rcommon.overlayImages(fixed_to_moving, moving, True) direct_residual, stats = tf.compose_vector_fields(displacement, direct_inverse) direct_residual = np.array(direct_residual) rcommon.plotDiffeomorphism(displacement, direct_inverse, direct_residual, "inv-direct", 7)
def testCircleToCMonomodalDiffeomorphic(lambdaParam): import numpy as np import tensorFieldUtils as tf import matplotlib.pyplot as plt import registrationCommon as rcommon fname0 = 'data/circle.png' #fname0='data/C_trans.png' fname1 = 'data/C.png' circleToCDisplacementName = 'circleToCDisplacement.npy' circleToCDisplacementInverseName = 'circleToCDisplacementInverse.npy' nib_moving = plt.imread(fname0) nib_fixed = plt.imread(fname1) moving = nib_moving[:, :, 0] fixed = nib_fixed[:, :, 1] moving = (moving - moving.min()) / (moving.max() - moving.min()) fixed = (fixed - fixed.min()) / (fixed.max() - fixed.min()) level = 3 maskMoving = moving > 0 maskFixed = fixed > 0 movingPyramid = [ img for img in rcommon.pyramid_gaussian_2D(moving, level, np.ones_like(maskMoving)) ] fixedPyramid = [ img for img in rcommon.pyramid_gaussian_2D(fixed, level, np.ones_like(maskFixed)) ] rcommon.plotOverlaidPyramids(movingPyramid, fixedPyramid) displacementList = [] maxOuterIter = [10, 50, 100, 100, 100, 100, 100, 100, 100] if (os.path.exists(circleToCDisplacementName)): displacement = np.load(circleToCDisplacementName) inverse = np.load(circleToCDisplacementInverseName) else: displacement, inverse = estimateMonomodalDiffeomorphicField2DMultiScale( movingPyramid, fixedPyramid, lambdaParam, maxOuterIter, 0, displacementList) np.save(circleToCDisplacementName, displacement) np.save(circleToCDisplacementInverseName, inverse) X1, X0 = np.mgrid[0:displacement.shape[0], 0:displacement.shape[1]] detJacobian = rcommon.computeJacobianField(displacement) plt.figure() plt.imshow(detJacobian) CS = plt.contour(X0, X1, detJacobian, levels=[0.0], colors='b') plt.clabel(CS, inline=1, fontsize=10) plt.title('det(J(displacement))') print 'J range:', '[', detJacobian.min(), detJacobian.max(), ']' #directInverse=np.array(tf.invert_vector_field(displacement, 0.5, 1000, 1e-7)) directInverse = np.array( tf.invert_vector_field_fixed_point(displacement, 100, 1e-7)) detJacobianInverse = rcommon.computeJacobianField(directInverse) plt.figure() plt.imshow(detJacobianInverse) CS = plt.contour(X0, X1, detJacobianInverse, levels=[0.0], colors='w') plt.clabel(CS, inline=1, fontsize=10) plt.title('det(J(displacement^-1))') print 'J^-1 range:', '[', detJacobianInverse.min(), detJacobianInverse.max( ), ']' #directInverse=rcommon.invert_vector_field_fixed_point(displacement, 1000, 1e-7) residual, stats = tf.compose_vector_fields(displacement, inverse) residual = np.array(residual) directResidual, stats = tf.compose_vector_fields(displacement, directInverse) directResidual = np.array(directResidual) # warpPyramid=[rcommon.warpImage(movingPyramid[i], displacementList[i]) for i in range(level+1)] # rcommon.plotOverlaidPyramids(warpPyramid, fixedPyramid) # rcommon.overlayImages(warpPyramid[0], fixedPyramid[0]) rcommon.plotDiffeomorphism(displacement, inverse, residual, 'inv-joint', 7) rcommon.plotDiffeomorphism(displacement, directInverse, directResidual, 'inv-direct', 7) tf.write_double_buffer(displacement.reshape(-1), 'displacement.bin')
def estimateNewMonomodalSyNField2D(moving, fixed, fWarp, fInv, mWarp, mInv, lambdaParam, maxOuterIter): ''' 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-4 outerTolerance = 1e-3 if (mWarp != None): totalM = mWarp totalMInv = mInv else: totalM = np.zeros(shape=(fixed.shape) + (2, ), dtype=np.float64) totalMInv = np.zeros(shape=(fixed.shape) + (2, ), dtype=np.float64) if (fWarp != None): totalF = fWarp totalFInv = fInv else: totalF = np.zeros(shape=(moving.shape) + (2, ), dtype=np.float64) totalFInv = np.zeros(shape=(moving.shape) + (2, ), dtype=np.float64) outerIter = 0 framesToCapture = 5 maxOuterIter = framesToCapture * ( (maxOuterIter + framesToCapture - 1) / framesToCapture) itersPerCapture = maxOuterIter / framesToCapture plt.figure() while (outerIter < maxOuterIter): outerIter += 1 print 'Outer iter:', outerIter wmoving = np.array(tf.warp_image(moving, totalMInv)) wfixed = np.array(tf.warp_image(fixed, totalFInv)) if ((outerIter == 1) or (outerIter % itersPerCapture == 0)): plt.subplot(1, framesToCapture + 1, 1 + outerIter / itersPerCapture) rcommon.overlayImages(wmoving, wfixed, False) plt.title('Iter:' + str(outerIter - 1)) #Compute forward update sigmaField = np.ones_like(wmoving, dtype=np.float64) deltaField = wfixed - wmoving movingGradient = np.empty(shape=(wmoving.shape) + (2, ), dtype=np.float64) movingGradient[:, :, 0], movingGradient[:, :, 1] = sp.gradient(wmoving) maxVariation = 1 + innerTolerance innerIter = 0 fw = np.zeros(shape=(fixed.shape) + (2, ), dtype=np.float64) maxInnerIter = 1000 while ((maxVariation > innerTolerance) and (innerIter < maxInnerIter)): innerIter += 1 maxVariation = tf.iterateDisplacementField2DCYTHON( deltaField, sigmaField, movingGradient, lambdaParam, fw, None) #fw*=0.5 totalF, stats = tf.compose_vector_fields(fw, totalF) totalF = np.array(totalF) meanDispF = np.mean(np.abs(fw)) #Compute backward field sigmaField = np.ones_like(wfixed, dtype=np.float64) deltaField = wmoving - wfixed fixedGradient = np.empty(shape=(wfixed.shape) + (2, ), dtype=np.float64) fixedGradient[:, :, 0], fixedGradient[:, :, 1] = sp.gradient(wfixed) maxVariation = 1 + innerTolerance innerIter = 0 mw = np.zeros(shape=(fixed.shape) + (2, ), dtype=np.float64) maxInnerIter = 1000 while ((maxVariation > innerTolerance) and (innerIter < maxInnerIter)): innerIter += 1 maxVariation = tf.iterateDisplacementField2DCYTHON( deltaField, sigmaField, fixedGradient, lambdaParam, mw, None) #mw*=0.5 totalM, stats = tf.compose_vector_fields(mw, totalM) totalM = np.array(totalM) meanDispM = np.mean(np.abs(mw)) totalFInv = np.array( tf.invert_vector_field_fixed_point(totalF, None, 20, 1e-3, None)) totalMInv = np.array( tf.invert_vector_field_fixed_point(totalM, None, 20, 1e-3, None)) totalF = np.array( tf.invert_vector_field_fixed_point(totalFInv, None, 20, 1e-3, None)) totalM = np.array( tf.invert_vector_field_fixed_point(totalMInv, None, 20, 1e-3, None)) # totalFInv=np.array(tf.invert_vector_field(totalF, 0.75, 100, 1e-6)) # totalMInv=np.array(tf.invert_vector_field(totalM, 0.75, 100, 1e-6)) # totalF=np.array(tf.invert_vector_field(totalFInv, 0.75, 100, 1e-6)) # totalM=np.array(tf.invert_vector_field(totalMInv, 0.75, 100, 1e-6)) if (meanDispM + meanDispF < 2 * outerTolerance): break print "Iter: ", innerIter, "Mean lateral displacement:", 0.5 * ( meanDispM + meanDispF), "Max variation:", maxVariation return totalF, totalFInv, totalM, totalMInv
def estimateNewMultimodalDiffeomorphicField2D(moving, fixed, lambdaDisplacement, quantizationLevels, maxOuterIter, previousDisplacement, previousDisplacementInverse): innerTolerance=1e-4 outerTolerance=1e-3 sh=moving.shape X0,X1=np.mgrid[0:sh[0], 0:sh[1]] displacement =np.empty(shape=(moving.shape)+(2,), dtype=np.float64) residuals=np.zeros(shape=(moving.shape), dtype=np.float64) gradientField =np.empty(shape=(moving.shape)+(2,), dtype=np.float64) totalDisplacement=np.zeros(shape=(moving.shape)+(2,), dtype=np.float64) totalDisplacementInverse=np.zeros(shape=(moving.shape)+(2,), dtype=np.float64) if(previousDisplacement!=None): totalDisplacement[...]=previousDisplacement totalDisplacementInverse[...]=previousDisplacementInverse fixedQ=None grayLevels=None fixedQ, grayLevels, hist=tf.quantizePositiveImageCYTHON(fixed, quantizationLevels) fixedQ=np.array(fixedQ, dtype=np.int32) finished=False outerIter=0 maxDisplacement=None maxVariation=None maxResidual=0 while((not finished) and (outerIter<maxOuterIter)): outerIter+=1 #---E step--- warped=ndimage.map_coordinates(moving, [X0+totalDisplacement[...,0], X1+totalDisplacement[...,1]], prefilter=True) movingMask=((moving>0)*1.0)*((fixed>0)*1.0) warpedMovingMask=ndimage.map_coordinates(movingMask, [X0+totalDisplacement[...,0], X1+totalDisplacement[...,1]], order=0, prefilter=False) warpedMovingMask=warpedMovingMask.astype(np.int32) means, variances=tf.computeMaskedImageClassStatsCYTHON(warpedMovingMask, 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=sp.gradient(warped) gradientField[:,:,0]=g0 gradientField[:,:,1]=g1 maxVariation=1+innerTolerance innerIter=0 maxInnerIter=1000 displacement[...]=0 while((maxVariation>innerTolerance)and(innerIter<maxInnerIter)): innerIter+=1 maxVariation=tf.iterateDisplacementField2DCYTHON(deltaField, sigmaField, gradientField, lambdaDisplacement, totalDisplacement, displacement, residuals) opt=np.max(residuals) if(maxResidual<opt): maxResidual=opt #--accumulate displacement-- expd, invexpd=tf.vector_field_exponential(displacement) totalDisplacement=tf.compose_vector_fields(expd, totalDisplacement) totalDisplacementInverse=tf.compose_vector_fields(totalDisplacementInverse, invexpd) #--check stop condition-- nrm=np.sqrt(displacement[...,0]**2+displacement[...,1]**2) #maxDisplacement=np.max(nrm) maxDisplacement=np.mean(nrm) if((maxDisplacement<outerTolerance)or(outerIter>=maxOuterIter)): finished=True # plt.figure() # plt.subplot(1,3,1) # plt.imshow(means[fixedQ],cmap=plt.cm.gray) # plt.title("Estimated warped modality") # plt.subplot(1,3,2) # plt.imshow(fixedQ,cmap=plt.cm.gray) # plt.title("Quantized") # plt.subplot(1,3,3) # plt.plot(means) # plt.title("Means") print "Iter: ",outerIter, "Mean displacement:", maxDisplacement, "Max variation:",maxVariation, "Max residual:", maxResidual if(previousDisplacement!=None): return totalDisplacement-previousDisplacement, totalDisplacementInverse return totalDisplacement, totalDisplacementInverse
def estimateNewMultimodalDiffeomorphicField2D(moving, fixed, lambdaDisplacement, quantizationLevels, maxOuterIter, previousDisplacement, previousDisplacementInverse): innerTolerance = 1e-4 outerTolerance = 1e-3 sh = moving.shape X0, X1 = np.mgrid[0:sh[0], 0:sh[1]] displacement = np.empty(shape=(moving.shape) + (2, ), dtype=np.float64) residuals = np.zeros(shape=(moving.shape), dtype=np.float64) gradientField = np.empty(shape=(moving.shape) + (2, ), dtype=np.float64) totalDisplacement = np.zeros(shape=(moving.shape) + (2, ), dtype=np.float64) totalDisplacementInverse = np.zeros(shape=(moving.shape) + (2, ), dtype=np.float64) if (previousDisplacement != None): totalDisplacement[...] = previousDisplacement totalDisplacementInverse[...] = previousDisplacementInverse fixedQ = None grayLevels = None fixedQ, grayLevels, hist = tf.quantizePositiveImageCYTHON( fixed, quantizationLevels) fixedQ = np.array(fixedQ, dtype=np.int32) finished = False outerIter = 0 maxDisplacement = None maxVariation = None maxResidual = 0 while ((not finished) and (outerIter < maxOuterIter)): outerIter += 1 #---E step--- warped = ndimage.map_coordinates( moving, [X0 + totalDisplacement[..., 0], X1 + totalDisplacement[..., 1]], prefilter=True) movingMask = ((moving > 0) * 1.0) * ((fixed > 0) * 1.0) warpedMovingMask = ndimage.map_coordinates( movingMask, [X0 + totalDisplacement[..., 0], X1 + totalDisplacement[..., 1]], order=0, prefilter=False) warpedMovingMask = warpedMovingMask.astype(np.int32) means, variances = tf.computeMaskedImageClassStatsCYTHON( warpedMovingMask, 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 = sp.gradient(warped) gradientField[:, :, 0] = g0 gradientField[:, :, 1] = g1 maxVariation = 1 + innerTolerance innerIter = 0 maxInnerIter = 1000 displacement[...] = 0 while ((maxVariation > innerTolerance) and (innerIter < maxInnerIter)): innerIter += 1 maxVariation = tf.iterateDisplacementField2DCYTHON( deltaField, sigmaField, gradientField, lambdaDisplacement, totalDisplacement, displacement, residuals) opt = np.max(residuals) if (maxResidual < opt): maxResidual = opt #--accumulate displacement-- expd, invexpd = tf.vector_field_exponential(displacement) totalDisplacement = tf.compose_vector_fields(expd, totalDisplacement) totalDisplacementInverse = tf.compose_vector_fields( totalDisplacementInverse, invexpd) #--check stop condition-- nrm = np.sqrt(displacement[..., 0]**2 + displacement[..., 1]**2) #maxDisplacement=np.max(nrm) maxDisplacement = np.mean(nrm) if ((maxDisplacement < outerTolerance) or (outerIter >= maxOuterIter)): finished = True # plt.figure() # plt.subplot(1,3,1) # plt.imshow(means[fixedQ],cmap=plt.cm.gray) # plt.title("Estimated warped modality") # plt.subplot(1,3,2) # plt.imshow(fixedQ,cmap=plt.cm.gray) # plt.title("Quantized") # plt.subplot(1,3,3) # plt.plot(means) # plt.title("Means") print "Iter: ", outerIter, "Mean displacement:", maxDisplacement, "Max variation:", maxVariation, "Max residual:", maxResidual if (previousDisplacement != None): return totalDisplacement - previousDisplacement, totalDisplacementInverse return totalDisplacement, totalDisplacementInverse
def runArcesExperiment(rootDir, lambdaParam, maxOuterIter): #---Load displacement field--- dxName = rootDir + 'Vx.dat' dyName = rootDir + 'Vy.dat' dx = np.loadtxt(dxName) dy = np.loadtxt(dyName) GT_in = np.ndarray(shape=dx.shape + (2, ), dtype=np.float64) GT_in[..., 0] = dy GT_in[..., 1] = dx GT, GTinv = tf.vector_field_exponential(GT_in) GTres = tf.compose_vector_fields(GT, GTinv) #---Load input images--- fnameT1 = rootDir + 't1.jpg' fnameT2 = rootDir + 't2.jpg' fnamePD = rootDir + 'pd.jpg' fnameMask = rootDir + 'Mascara.bmp' t1 = plt.imread(fnameT1)[..., 0].astype(np.float64) t2 = plt.imread(fnameT2)[..., 0].astype(np.float64) pd = plt.imread(fnamePD)[..., 0].astype(np.float64) t1 = (t1 - t1.min()) / (t1.max() - t1.min()) t2 = (t2 - t2.min()) / (t2.max() - t2.min()) pd = (pd - pd.min()) / (pd.max() - pd.min()) mask = plt.imread(fnameMask).astype(np.float64) fixed = t1 moving = t2 maskMoving = mask > 0 maskFixed = mask > 0 fixed *= mask moving *= mask plt.figure() plt.subplot(1, 4, 1) plt.imshow(t1, cmap=plt.cm.gray) plt.title('Input T1') plt.subplot(1, 4, 2) plt.imshow(t2, cmap=plt.cm.gray) plt.title('Input T2') plt.subplot(1, 4, 3) plt.imshow(pd, cmap=plt.cm.gray) plt.title('Input PD') plt.subplot(1, 4, 4) plt.imshow(mask, cmap=plt.cm.gray) plt.title('Input Mask') #------------------------- warpedFixed = rcommon.warpImage(fixed, GT) print 'Registering T2 (template) to deformed T1 (template)...' level = 3 movingPyramid = [ img for img in rcommon.pyramid_gaussian_2D(moving, level, maskMoving) ] fixedPyramid = [ img for img in rcommon.pyramid_gaussian_2D(warpedFixed, level, maskFixed) ] plt.figure() plt.subplot(1, 2, 1) plt.imshow(moving, cmap=plt.cm.gray) plt.title('Moving') plt.subplot(1, 2, 2) plt.imshow(warpedFixed, cmap=plt.cm.gray) plt.title('Fixed') rcommon.plotOverlaidPyramids(movingPyramid, fixedPyramid) displacementList = [] displacement, inverse = estimateMultimodalDiffeomorphicField2DMultiScale( movingPyramid, fixedPyramid, lambdaParam, maxOuterIter, 0, displacementList) residual = tf.compose_vector_fields(displacement, inverse) warpPyramid = [ rcommon.warpImage(movingPyramid[i], displacementList[i]) for i in range(level + 1) ] rcommon.plotOverlaidPyramids(warpPyramid, fixedPyramid) rcommon.overlayImages(warpPyramid[0], fixedPyramid[0]) displacement[..., 0] *= (maskFixed) displacement[..., 1] *= (maskFixed) #----plot deformations--- rcommon.plotDiffeomorphism(GT, GTinv, GTres, 7) rcommon.plotDiffeomorphism(displacement, inverse, residual, 7) #----statistics--- nrm = np.sqrt(displacement[..., 0]**2 + displacement[..., 1]**2) nrm *= maskFixed maxNorm = np.max(nrm) residual = ((displacement - GT))**2 meanDisplacementError = np.sqrt(residual.sum(2) * (maskFixed)).mean() stdevDisplacementError = np.sqrt(residual.sum(2) * (maskFixed)).std() print 'Max global displacement: ', maxNorm print 'Mean displacement error: ', meanDisplacementError, '(', stdevDisplacementError, ')'
def testInversion(lambdaParam): fname0 = 'data/circle.png' fname1 = 'data/C.png' circleToCDisplacementName = 'circleToCDisplacement.npy' circleToCDisplacementInverseName = 'circleToCDisplacementInverse.npy' nib_moving = plt.imread(fname0) nib_fixed = plt.imread(fname1) moving = nib_moving[:, :, 0] fixed = nib_fixed[:, :, 1] moving = (moving - moving.min()) / (moving.max() - moving.min()) fixed = (fixed - fixed.min()) / (fixed.max() - fixed.min()) level = 3 maskMoving = moving > 0 maskFixed = fixed > 0 movingPyramid = [ img for img in rcommon.pyramid_gaussian_2D(moving, level, np.ones_like(maskMoving)) ] fixedPyramid = [ img for img in rcommon.pyramid_gaussian_2D(fixed, level, np.ones_like(maskFixed)) ] rcommon.plotOverlaidPyramids(movingPyramid, fixedPyramid) displacementList = [] maxOuterIter = [10, 50, 100, 100, 100, 100, 100, 100, 100] if (os.path.exists(circleToCDisplacementName)): displacement = np.load(circleToCDisplacementName) inverse = np.load(circleToCDisplacementInverseName) else: displacement, inverse = estimateMonomodalDiffeomorphicField2DMultiScale( movingPyramid, fixedPyramid, lambdaParam, maxOuterIter, 0, displacementList) np.save(circleToCDisplacementName, displacement) np.save(circleToCDisplacementInverseName, inverse) print 'vector field exponential' expd, invexpd = tf.vector_field_exponential(displacement, True) print 'vector field inversion' directInverse = tf.invert_vector_field(displacement, 1.0, 10000, 1e-7) print 'vector field inversion' directExpInverse = tf.invert_vector_field(expd, 1.0, 10000, 1e-7) ###Now compare inversions### residualJoint = np.array( tf.compose_vector_fields(displacement, inverse)[0]) residualDirect = np.array( tf.compose_vector_fields(displacement, directInverse)[0]) residualExpJoint = np.array(tf.compose_vector_fields(expd, invexpd)[0]) residualExpDirect = np.array( tf.compose_vector_fields(expd, directExpInverse)[0]) rcommon.plotDiffeomorphism(displacement, inverse, residualJoint, 'D-joint') rcommon.plotDiffeomorphism(expd, invexpd, residualExpJoint, 'expD-joint') d, invd, res, jacobian = rcommon.plotDiffeomorphism( displacement, directInverse, residualDirect, 'D-direct') rcommon.plotDiffeomorphism(expd, directExpInverse, residualExpDirect, 'expD-direct') sp.misc.imsave('circleToC_deformation.png', d) sp.misc.imsave('circleToC_inverse_deformation.png', invd) sp.misc.imsave('circleToC_residual_deformation.png', res) tf.write_double_buffer( np.array(displacement).reshape(-1), '../inverse/experiments/displacement.bin') tf.write_double_buffer( np.array(displacement).reshape(-1), '../inverse/experiments/displacement_clean.bin')
def runArcesExperiment(rootDir, lambdaParam, maxOuterIter): #---Load displacement field--- dxName=rootDir+'Vx.dat' dyName=rootDir+'Vy.dat' dx=np.loadtxt(dxName) dy=np.loadtxt(dyName) GT_in=np.ndarray(shape=dx.shape+(2,), dtype=np.float64) GT_in[...,0]=dy GT_in[...,1]=dx GT, GTinv=tf.vector_field_exponential(GT_in) GTres=tf.compose_vector_fields(GT, GTinv) #---Load input images--- fnameT1=rootDir+'t1.jpg' fnameT2=rootDir+'t2.jpg' fnamePD=rootDir+'pd.jpg' fnameMask=rootDir+'Mascara.bmp' t1=plt.imread(fnameT1)[...,0].astype(np.float64) t2=plt.imread(fnameT2)[...,0].astype(np.float64) pd=plt.imread(fnamePD)[...,0].astype(np.float64) t1=(t1-t1.min())/(t1.max()-t1.min()) t2=(t2-t2.min())/(t2.max()-t2.min()) pd=(pd-pd.min())/(pd.max()-pd.min()) mask=plt.imread(fnameMask).astype(np.float64) fixed=t1 moving=t2 maskMoving=mask>0 maskFixed=mask>0 fixed*=mask moving*=mask plt.figure() plt.subplot(1,4,1) plt.imshow(t1, cmap=plt.cm.gray) plt.title('Input T1') plt.subplot(1,4,2) plt.imshow(t2, cmap=plt.cm.gray) plt.title('Input T2') plt.subplot(1,4,3) plt.imshow(pd, cmap=plt.cm.gray) plt.title('Input PD') plt.subplot(1,4,4) plt.imshow(mask, cmap=plt.cm.gray) plt.title('Input Mask') #------------------------- warpedFixed=rcommon.warpImage(fixed,GT) print 'Registering T2 (template) to deformed T1 (template)...' level=3 movingPyramid=[img for img in rcommon.pyramid_gaussian_2D(moving, level, maskMoving)] fixedPyramid=[img for img in rcommon.pyramid_gaussian_2D(warpedFixed, level, maskFixed)] plt.figure() plt.subplot(1,2,1) plt.imshow(moving, cmap=plt.cm.gray) plt.title('Moving') plt.subplot(1,2,2) plt.imshow(warpedFixed, cmap=plt.cm.gray) plt.title('Fixed') rcommon.plotOverlaidPyramids(movingPyramid, fixedPyramid) displacementList=[] displacement, inverse=estimateMultimodalDiffeomorphicField2DMultiScale(movingPyramid, fixedPyramid, lambdaParam, maxOuterIter, 0, displacementList) residual=tf.compose_vector_fields(displacement, inverse) warpPyramid=[rcommon.warpImage(movingPyramid[i], displacementList[i]) for i in range(level+1)] rcommon.plotOverlaidPyramids(warpPyramid, fixedPyramid) rcommon.overlayImages(warpPyramid[0], fixedPyramid[0]) displacement[...,0]*=(maskFixed) displacement[...,1]*=(maskFixed) #----plot deformations--- rcommon.plotDiffeomorphism(GT, GTinv, GTres, 7) rcommon.plotDiffeomorphism(displacement, inverse, residual, 7) #----statistics--- nrm=np.sqrt(displacement[...,0]**2 + displacement[...,1]**2) nrm*=maskFixed maxNorm=np.max(nrm) residual=((displacement-GT))**2 meanDisplacementError=np.sqrt(residual.sum(2)*(maskFixed)).mean() stdevDisplacementError=np.sqrt(residual.sum(2)*(maskFixed)).std() print 'Max global displacement: ', maxNorm print 'Mean displacement error: ', meanDisplacementError,'(',stdevDisplacementError,')'
def estimateNewMonomodalSyNField2D(moving, fixed, fWarp, fInv, mWarp, mInv, lambdaParam, maxOuterIter): ''' 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-4 outerTolerance=1e-3 if(mWarp!=None): totalM=mWarp totalMInv=mInv else: totalM=np.zeros(shape=(fixed.shape)+(2,), dtype=np.float64) totalMInv=np.zeros(shape=(fixed.shape)+(2,), dtype=np.float64) if(fWarp!=None): totalF=fWarp totalFInv=fInv else: totalF=np.zeros(shape=(moving.shape)+(2,), dtype=np.float64) totalFInv=np.zeros(shape=(moving.shape)+(2,), dtype=np.float64) outerIter=0 framesToCapture=5 maxOuterIter=framesToCapture*((maxOuterIter+framesToCapture-1)/framesToCapture) itersPerCapture=maxOuterIter/framesToCapture plt.figure() while(outerIter<maxOuterIter): outerIter+=1 print 'Outer iter:', outerIter wmoving=np.array(tf.warp_image(moving, totalMInv)) wfixed=np.array(tf.warp_image(fixed, totalFInv)) if((outerIter==1) or (outerIter%itersPerCapture==0)): plt.subplot(1,framesToCapture+1, 1+outerIter/itersPerCapture) rcommon.overlayImages(wmoving, wfixed, False) plt.title('Iter:'+str(outerIter-1)) #Compute forward update sigmaField=np.ones_like(wmoving, dtype=np.float64) deltaField=wfixed-wmoving movingGradient =np.empty(shape=(wmoving.shape)+(2,), dtype=np.float64) movingGradient[:,:,0], movingGradient[:,:,1]=sp.gradient(wmoving) maxVariation=1+innerTolerance innerIter=0 fw =np.zeros(shape=(fixed.shape)+(2,), dtype=np.float64) maxInnerIter=1000 while((maxVariation>innerTolerance)and(innerIter<maxInnerIter)): innerIter+=1 maxVariation=tf.iterateDisplacementField2DCYTHON(deltaField, sigmaField, movingGradient, lambdaParam, fw, None) #fw*=0.5 totalF, stats=tf.compose_vector_fields(fw, totalF) totalF=np.array(totalF); meanDispF=np.mean(np.abs(fw)) #Compute backward field sigmaField=np.ones_like(wfixed, dtype=np.float64) deltaField=wmoving-wfixed fixedGradient =np.empty(shape=(wfixed.shape)+(2,), dtype=np.float64) fixedGradient[:,:,0], fixedGradient[:,:,1]=sp.gradient(wfixed) maxVariation=1+innerTolerance innerIter=0 mw =np.zeros(shape=(fixed.shape)+(2,), dtype=np.float64) maxInnerIter=1000 while((maxVariation>innerTolerance)and(innerIter<maxInnerIter)): innerIter+=1 maxVariation=tf.iterateDisplacementField2DCYTHON(deltaField, sigmaField, fixedGradient, lambdaParam, mw, None) #mw*=0.5 totalM, stats=tf.compose_vector_fields(mw, totalM) totalM=np.array(totalM); meanDispM=np.mean(np.abs(mw)) totalFInv=np.array(tf.invert_vector_field_fixed_point(totalF, None, 20, 1e-3, None)) totalMInv=np.array(tf.invert_vector_field_fixed_point(totalM, None, 20, 1e-3, None)) totalF=np.array(tf.invert_vector_field_fixed_point(totalFInv, None, 20, 1e-3, None)) totalM=np.array(tf.invert_vector_field_fixed_point(totalMInv, None, 20, 1e-3, None)) # totalFInv=np.array(tf.invert_vector_field(totalF, 0.75, 100, 1e-6)) # totalMInv=np.array(tf.invert_vector_field(totalM, 0.75, 100, 1e-6)) # totalF=np.array(tf.invert_vector_field(totalFInv, 0.75, 100, 1e-6)) # totalM=np.array(tf.invert_vector_field(totalMInv, 0.75, 100, 1e-6)) if(meanDispM+meanDispF<2*outerTolerance): break print "Iter: ",innerIter, "Mean lateral displacement:", 0.5*(meanDispM+meanDispF), "Max variation:",maxVariation return totalF, totalFInv, totalM, totalMInv
def update(new_displacement, current_displacement): expd, invexpd = tf.vector_field_exponential(new_displacement, True) updated, stats = tf.compose_vector_fields(expd, current_displacement) return updated, stats[0]
def test_optimizer_multimodal_2d(lambda_param): r''' Registers one of the mid-slices (axial, coronal or sagital) of each input volume (the volumes are expected to be from diferent modalities and should already be affine-registered, for example Brainweb t1 vs t2) ''' fname_moving = 'data/t2/IBSR_t2template_to_01.nii.gz' fname_fixed = 'data/t1/IBSR_template_to_01.nii.gz' # fnameMoving = 'data/circle.png' # fnameFixed = 'data/C.png' nifti = True if nifti: nib_moving = nib.load(fname_moving) nib_fixed = nib.load(fname_fixed) moving = nib_moving.get_data().squeeze().astype(np.float64) fixed = nib_fixed.get_data().squeeze().astype(np.float64) moving = np.copy(moving, order='C') fixed = np.copy(fixed, order='C') shape_moving = moving.shape shape_fixed = fixed.shape moving = moving[:, shape_moving[1] // 2, :].copy() fixed = fixed[:, shape_fixed[1] // 2, :].copy() moving = (moving - moving.min()) / (moving.max() - moving.min()) fixed = (fixed - fixed.min()) / (fixed.max() - fixed.min()) else: nib_moving = plt.imread(fname_moving) nib_fixed = plt.imread(fname_fixed) moving = nib_moving[:, :, 0].astype(np.float64) fixed = nib_fixed[:, :, 1].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()) max_iter = [i for i in [25, 50, 100]] similarity_metric = EMMetric( 2, { 'symmetric': True, 'lambda': lambda_param, 'stepType': SSDMetric.GAUSS_SEIDEL_STEP, 'q_levels': 256, 'max_inner_iter': 20, 'use_double_gradient': True, 'max_step_length': 0.25 }) optimizer_parameters = { 'max_iter': max_iter, 'inversion_iter': 20, 'inversion_tolerance': 1e-3, 'report_status': True } update_rule = UpdateRule.Composition() print('Generating synthetic field...') #----apply synthetic deformation field to fixed image ground_truth = rcommon.createDeformationField2D_type2( fixed.shape[0], fixed.shape[1], 8) warped_fixed = rcommon.warpImage(fixed, ground_truth) print('Registering T2 (template) to deformed T1 (template)...') plt.figure() rcommon.overlayImages(warped_fixed, moving, False) registration_optimizer = SymmetricRegistrationOptimizer( warped_fixed, moving, None, None, similarity_metric, update_rule, optimizer_parameters) registration_optimizer.optimize() #######################show results################################# displacement = registration_optimizer.get_forward() direct_inverse = registration_optimizer.get_backward() moving_to_fixed = np.array(tf.warp_image(moving, displacement)) fixed_to_moving = np.array(tf.warp_image(warped_fixed, direct_inverse)) rcommon.overlayImages(moving_to_fixed, fixed_to_moving, True) direct_residual, stats = tf.compose_vector_fields(displacement, direct_inverse) direct_residual = np.array(direct_residual) rcommon.plotDiffeomorphism(displacement, direct_inverse, direct_residual, 'inv-direct', 7) residual = ((displacement - ground_truth))**2 mean_displacement_error = np.sqrt(residual.sum(2) * (warped_fixed > 0)).mean() stdev_displacement_error = np.sqrt(residual.sum(2) * (warped_fixed > 0)).std() print('Mean displacement error: %0.6f (%0.6f)' % (mean_displacement_error, stdev_displacement_error))
def test_optimizer_multimodal_2d(lambda_param): r''' Registers one of the mid-slices (axial, coronal or sagital) of each input volume (the volumes are expected to be from diferent modalities and should already be affine-registered, for example Brainweb t1 vs t2) ''' fname_moving = 'data/t2/IBSR_t2template_to_01.nii.gz' fname_fixed = 'data/t1/IBSR_template_to_01.nii.gz' # fnameMoving = 'data/circle.png' # fnameFixed = 'data/C.png' nifti = True if nifti: nib_moving = nib.load(fname_moving) nib_fixed = nib.load(fname_fixed) moving = nib_moving.get_data().squeeze().astype(np.float64) fixed = nib_fixed.get_data().squeeze().astype(np.float64) moving = np.copy(moving, order = 'C') fixed = np.copy(fixed, order = 'C') shape_moving = moving.shape shape_fixed = fixed.shape moving = moving[:, shape_moving[1]//2, :].copy() fixed = fixed[:, shape_fixed[1]//2, :].copy() moving = (moving-moving.min())/(moving.max()-moving.min()) fixed = (fixed-fixed.min())/(fixed.max()-fixed.min()) else: nib_moving = plt.imread(fname_moving) nib_fixed = plt.imread(fname_fixed) moving = nib_moving[:, :, 0].astype(np.float64) fixed = nib_fixed[:, :, 1].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()) max_iter = [i for i in [25, 50, 100]] similarity_metric = EMMetric(2, {'symmetric':True, 'lambda':lambda_param, 'stepType':SSDMetric.GAUSS_SEIDEL_STEP, 'q_levels':256, 'max_inner_iter':20, 'use_double_gradient':True, 'max_step_length':0.25}) optimizer_parameters = { 'max_iter':max_iter, 'inversion_iter':20, 'inversion_tolerance':1e-3, 'report_status':True} update_rule = UpdateRule.Composition() print('Generating synthetic field...') #----apply synthetic deformation field to fixed image ground_truth = rcommon.createDeformationField2D_type2(fixed.shape[0], fixed.shape[1], 8) warped_fixed = rcommon.warpImage(fixed, ground_truth) print('Registering T2 (template) to deformed T1 (template)...') plt.figure() rcommon.overlayImages(warped_fixed, moving, False) registration_optimizer = SymmetricRegistrationOptimizer(warped_fixed, moving, None, None, similarity_metric, update_rule, optimizer_parameters) registration_optimizer.optimize() #######################show results################################# displacement = registration_optimizer.get_forward() direct_inverse = registration_optimizer.get_backward() moving_to_fixed = np.array(tf.warp_image(moving, displacement)) fixed_to_moving = np.array(tf.warp_image(warped_fixed, direct_inverse)) rcommon.overlayImages(moving_to_fixed, fixed_to_moving, True) direct_residual, stats = tf.compose_vector_fields(displacement, direct_inverse) direct_residual = np.array(direct_residual) rcommon.plotDiffeomorphism(displacement, direct_inverse, direct_residual, 'inv-direct', 7) residual = ((displacement-ground_truth))**2 mean_displacement_error = np.sqrt(residual.sum(2)*(warped_fixed>0)).mean() stdev_displacement_error = np.sqrt(residual.sum(2)*(warped_fixed>0)).std() print('Mean displacement error: %0.6f (%0.6f)'% (mean_displacement_error, stdev_displacement_error))
def test_optimizer_multimodal_2d(lambda_param): r""" Registers one of the mid-slices (axial, coronal or sagital) of each input volume (the volumes are expected to be from diferent modalities and should already be affine-registered, for example Brainweb t1 vs t2) """ fname_moving = "data/t2/IBSR_t2template_to_01.nii.gz" fname_fixed = "data/t1/IBSR_template_to_01.nii.gz" # fname_moving = 'data/circle.png' # fname_fixed = 'data/C.png' nifti = True if nifti: nib_moving = nib.load(fname_moving) nib_fixed = nib.load(fname_fixed) moving = nib_moving.get_data().squeeze().astype(np.float64) fixed = nib_fixed.get_data().squeeze().astype(np.float64) moving = np.copy(moving, order="C") fixed = np.copy(fixed, order="C") moving_shape = moving.shape fixed_shape = fixed.shape moving = moving[:, moving_shape[1] // 2, :].copy() fixed = fixed[:, fixed_shape[1] // 2, :].copy() # moving = histeq(moving) # fixed = histeq(fixed) moving = (moving - moving.min()) / (moving.max() - moving.min()) fixed = (fixed - fixed.min()) / (fixed.max() - fixed.min()) else: nib_moving = plt.imread(fname_moving) nib_fixed = plt.imread(fname_fixed) moving = nib_moving[:, :, 0].astype(np.float64) fixed = nib_fixed[:, :, 1].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()) # max_iter = [i for i in [25,50,100,100]] max_iter = [i for i in [25, 50, 100]] similarity_metric = EMMetric( { "symmetric": True, "lambda": lambda_param, "step_type": SSDMetric.GAUSS_SEIDEL_STEP, "q_levels": 256, "max_inner_iter": 40, "use_double_gradient": True, "max_step_length": 0.25, } ) optimizer_parameters = { "max_iter": max_iter, "inversion_iter": 40, "inversion_tolerance": 1e-3, "report_status": True, } update_rule = UpdateRule.Composition() print "Generating synthetic field..." # ----apply synthetic deformation field to fixed image ground_truth = rcommon.createDeformationField2D_type2(fixed.shape[0], fixed.shape[1], 8) warped_fixed = rcommon.warpImage(fixed, ground_truth) print "Registering T2 (template) to deformed T1 (template)..." plt.figure() rcommon.overlayImages(warped_fixed, moving, False) registration_optimizer = AsymmetricRegistrationOptimizer( warped_fixed, moving, None, None, similarity_metric, update_rule, optimizer_parameters ) registration_optimizer.optimize() #######################show results################################# displacement = registration_optimizer.get_forward() direct_inverse = registration_optimizer.get_backward() moving_to_fixed = np.array(tf.warp_image(moving, displacement)) fixed_to_moving = np.array(tf.warp_image(warped_fixed, direct_inverse)) rcommon.overlayImages(moving_to_fixed, fixed_to_moving, True) direct_residual, stats = tf.compose_vector_fields(displacement, direct_inverse) direct_residual = np.array(direct_residual) rcommon.plotDiffeomorphism(displacement, direct_inverse, direct_residual, "inv-direct", 7) residual = ((displacement - ground_truth)) ** 2 mean_error = np.sqrt(residual.sum(2) * (warped_fixed > 0)).mean() stdev_error = np.sqrt(residual.sum(2) * (warped_fixed > 0)).std() print "Mean displacement error: ", mean_error, "(", stdev_error, ")"