class SyN(Registration): def set_vector_fields(self, shape): assert self.n_step % 2 == 0 self.n_step_half = self.n_step / 2 # moving -> midpoint self.forward_vector_fields = VectorFields(self.n_step_half, shape) # midpoint <- fixed self.backward_vector_fields = VectorFields(self.n_step_half, shape) def get_forward_mapping_inverse(self): inverse_mapping = identity_mapping(self.forward_vector_fields.shape) v = -0.5 * (self.forward_vector_fields[-2::-1] + self.forward_vector_fields[:0:-1]) for i in xrange(self.n_step_half): inverse_mapping = inverse_mapping - np.einsum( 'ij...,j...->i...', jacobian_matrix(inverse_mapping), v[i]) / self.n_step return inverse_mapping def get_backward_mapping_inverse(self): inverse_mapping = identity_mapping(self.backward_vector_fields.shape) v = -0.5 * (self.backward_vector_fields[-2::-1] + self.backward_vector_fields[:0:-1]) for i in xrange(self.n_step_half): inverse_mapping = inverse_mapping - np.einsum( 'ij...,j...->i...', jacobian_matrix(inverse_mapping), v[i]) / self.n_step return inverse_mapping def update(self, fixed, moving): if self.n_jobs != 1: self.update_parallel(fixed, moving) else: self.update_sequential(fixed, moving) def update_sequential(self, fixed, moving): for i in xrange(self.n_step_half + 1): j = -i - 1 # moving -> midpoint momentum = (self.similarity.derivative(fixed[j], moving[i]) * self.deformation.backward_dets[j]) grad = self.learning_rate * (2 * self.forward_vector_fields[i] + self.regularizer(momentum)) self.forward_vector_fields.delta_vector_fields[i] = np.copy(grad) # midpoint <- fixed momentum = (self.similarity.derivative(moving[j], fixed[i]) * self.deformation.forward_dets[j]) grad = self.learning_rate * (2 * self.backward_vector_fields[i] + self.regularizer(momentum)) self.backward_vector_fields.delta_vector_fields[i] = np.copy(grad) self.forward_vector_fields.update() self.backward_vector_fields.update() self.integrate_vector_fields() def update_parallel(self, fixed, moving): if hasattr(self.regularizer, "set_operator"): self.regularizer.set_operator(shape=fixed.shape) self.forward_vector_fields.delta_vector_fields = np.array( Parallel(self.n_jobs)(delayed(derivative)(self.similarity, fixed[ -i - 1], moving[i], self.deformation.backward_dets[ -i - 1], self.forward_vector_fields[i], self.regularizer, self.learning_rate) for i in xrange(self.n_step_half + 1))) self.backward_vector_fields.delta_vector_fields = np.array( Parallel(self.n_jobs)(delayed(derivative)(self.similarity, moving[ -i - 1], fixed[i], self.deformation.forward_dets[ -i - 1], self.backward_vector_fields[i], self.regularizer, self.learning_rate) for i in xrange(self.n_step_half + 1))) self.forward_vector_fields.update() self.backward_vector_fields.update() self.integrate_vector_fields() def integrate_vector_fields(self): v_forward = 0.5 * (self.forward_vector_fields[:-1] + self.forward_vector_fields[1:]) v_backward = 0.5 * (self.backward_vector_fields[:-1] + self.backward_vector_fields[1:]) v = np.vstack((v_forward, -v_backward)) forward_mapping_before = np.copy( self.deformation.forward_mappings[self.n_step_half]) backward_mapping_before = np.copy( self.deformation.backward_mappings[self.n_step_half]) self.deformation.update_mappings(v) forward_mapping = self.deformation.forward_mappings[self.n_step_half] backward_mapping = self.deformation.backward_mappings[self.n_step_half] delta_phi_forward = np.max( np.abs(forward_mapping - forward_mapping_before)) delta_phi_backward = np.max( np.abs(backward_mapping - backward_mapping_before)) self.delta_phi = max(delta_phi_forward, delta_phi_backward) def execute(self): forward_warp = Deformation(shape=self.shape) backward_warp = Deformation(shape=self.shape) forward_warp_inv = Deformation(shape=self.shape) backward_warp_inv = Deformation(shape=self.shape) for n_iter, resolution, sigma in zip(self.n_iters, self.resolutions, self.smoothing_sigmas): print "=======================================" print "resolution", resolution warped_moving = self.moving.apply_transform(forward_warp) warped_fixed = self.fixed.apply_transform(backward_warp) moving = warped_moving.change_resolution(resolution, sigma) fixed = warped_fixed.change_resolution(resolution, sigma) shape = moving.get_shape() self.deformation.set_shape(shape) self.set_vector_fields(shape) mappings = self.optimization(fixed, moving, n_iter, resolution) forward_warp += mappings[0] backward_warp += mappings[1] forward_warp_inv = mappings[2] + forward_warp_inv backward_warp_inv = mappings[3] + backward_warp_inv return forward_warp + backward_warp_inv def optimization(self, fixed, moving, max_iter, resolution): fixed_images = SequentialScalarImages(fixed, self.n_step + 1) moving_images = SequentialScalarImages(moving, self.n_step + 1) print "iteration 0, Energy %f" % (self.similarity.cost( fixed.data, moving.data)) for i in xrange(max_iter): self.update(fixed_images, moving_images) if not self.check_injectivity(): break if self.n_jobs != 1: moving_images.apply_transforms_parallel( self.deformation.forward_mappings, self.n_jobs) fixed_images.apply_transforms_parallel( self.deformation.backward_mappings, self.n_jobs) else: moving_images.apply_transforms( self.deformation.forward_mappings) fixed_images.apply_transforms( self.deformation.backward_mappings) max_delta_phi = self.delta_phi * (max_iter - i) print "iteration%4d, Energy %f" % ( i + 1, self.similarity.cost(fixed_images[self.n_step_half], moving_images[self.n_step_half])) print 14 * ' ', "minimum unit", self.min_unit print 14 * ' ', "delta phi", self.delta_phi print 14 * ' ', "maximum delta phi", max_delta_phi if max_delta_phi < self.delta_phi_threshold / resolution: print "|L_inf norm of displacement| x iter < %f voxel" % ( self.delta_phi_threshold / resolution) break forward_mapping = self.zoom_grid( self.deformation.forward_mappings[self.n_step_half], resolution) backward_mapping = self.zoom_grid( self.deformation.backward_mappings[self.n_step_half], resolution) forward_mapping_inverse = self.zoom_grid( self.get_forward_mapping_inverse(), resolution) backward_mapping_inverse = self.zoom_grid( self.get_backward_mapping_inverse(), resolution) return (Deformation(grid=forward_mapping), Deformation(grid=backward_mapping), Deformation(grid=forward_mapping_inverse), Deformation(grid=backward_mapping_inverse))
class SyN(Registration): def set_vector_fields(self, shape): assert self.n_step % 2 == 0 self.n_step_half = self.n_step / 2 # moving -> midpoint self.forward_vector_fields = VectorFields(self.n_step_half, shape) # midpoint <- fixed self.backward_vector_fields = VectorFields(self.n_step_half, shape) def get_forward_mapping_inverse(self): inverse_mapping = identity_mapping(self.forward_vector_fields.shape) v = - 0.5 * (self.forward_vector_fields[-2::-1] + self.forward_vector_fields[:0:-1]) for i in xrange(self.n_step_half): inverse_mapping = inverse_mapping - np.einsum( 'ij...,j...->i...', jacobian_matrix(inverse_mapping), v[i]) / self.n_step return inverse_mapping def get_backward_mapping_inverse(self): inverse_mapping = identity_mapping(self.backward_vector_fields.shape) v = - 0.5 * (self.backward_vector_fields[-2::-1] + self.backward_vector_fields[:0:-1]) for i in xrange(self.n_step_half): inverse_mapping = inverse_mapping - np.einsum( 'ij...,j...->i...', jacobian_matrix(inverse_mapping), v[i]) / self.n_step return inverse_mapping def update(self, fixed, moving): if self.n_jobs != 1: self.update_parallel(fixed, moving) else: self.update_sequential(fixed, moving) def update_sequential(self, fixed, moving): for i in xrange(self.n_step_half + 1): j = -i - 1 # moving -> midpoint momentum = (self.similarity.derivative(fixed[j], moving[i]) * self.deformation.backward_dets[j]) grad = self.learning_rate * ( 2*self.forward_vector_fields[i] + self.regularizer(momentum) ) self.forward_vector_fields.delta_vector_fields[i] = np.copy(grad) # midpoint <- fixed momentum = (self.similarity.derivative(moving[j], fixed[i]) * self.deformation.forward_dets[j]) grad = self.learning_rate * ( 2*self.backward_vector_fields[i] + self.regularizer(momentum) ) self.backward_vector_fields.delta_vector_fields[i] = np.copy(grad) self.forward_vector_fields.update() self.backward_vector_fields.update() self.integrate_vector_fields() def update_parallel(self, fixed, moving): if hasattr(self.regularizer, "set_operator"): self.regularizer.set_operator(shape=fixed.shape) self.forward_vector_fields.delta_vector_fields = np.array( Parallel(self.n_jobs)( delayed(derivative)( self.similarity, fixed[-i - 1], moving[i], self.deformation.backward_dets[-i - 1], self.forward_vector_fields[i], self.regularizer, self.learning_rate) for i in xrange(self.n_step_half + 1) ) ) self.backward_vector_fields.delta_vector_fields = np.array( Parallel(self.n_jobs)( delayed(derivative)( self.similarity, moving[-i - 1], fixed[i], self.deformation.forward_dets[-i - 1], self.backward_vector_fields[i], self.regularizer, self.learning_rate) for i in xrange(self.n_step_half + 1) ) ) self.forward_vector_fields.update() self.backward_vector_fields.update() self.integrate_vector_fields() def integrate_vector_fields(self): v_forward = 0.5 * (self.forward_vector_fields[:-1] + self.forward_vector_fields[1:]) v_backward = 0.5 * (self.backward_vector_fields[:-1] + self.backward_vector_fields[1:]) v = np.vstack((v_forward, -v_backward)) forward_mapping_before = np.copy( self.deformation.forward_mappings[self.n_step_half]) backward_mapping_before = np.copy( self.deformation.backward_mappings[self.n_step_half]) self.deformation.update_mappings(v) forward_mapping = self.deformation.forward_mappings[self.n_step_half] backward_mapping = self.deformation.backward_mappings[self.n_step_half] delta_phi_forward = np.max(np.abs( forward_mapping - forward_mapping_before)) delta_phi_backward = np.max(np.abs( backward_mapping - backward_mapping_before)) self.delta_phi = max(delta_phi_forward, delta_phi_backward) def execute(self): forward_warp = Deformation(shape=self.shape) backward_warp = Deformation(shape=self.shape) forward_warp_inv = Deformation(shape=self.shape) backward_warp_inv = Deformation(shape=self.shape) for n_iter, resolution, sigma in zip(self.n_iters, self.resolutions, self.smoothing_sigmas): print "=======================================" print "resolution", resolution warped_moving = self.moving.apply_transform(forward_warp) warped_fixed = self.fixed.apply_transform(backward_warp) moving = warped_moving.change_resolution(resolution, sigma) fixed = warped_fixed.change_resolution(resolution, sigma) shape = moving.get_shape() self.deformation.set_shape(shape) self.set_vector_fields(shape) mappings = self.optimization(fixed, moving, n_iter, resolution) forward_warp += mappings[0] backward_warp += mappings[1] forward_warp_inv = mappings[2] + forward_warp_inv backward_warp_inv = mappings[3] + backward_warp_inv return forward_warp + backward_warp_inv def optimization(self, fixed, moving, max_iter, resolution): fixed_images = SequentialScalarImages(fixed, self.n_step + 1) moving_images = SequentialScalarImages(moving, self.n_step + 1) print "iteration 0, Energy %f" % ( self.similarity.cost(fixed.data, moving.data)) for i in xrange(max_iter): self.update(fixed_images, moving_images) if not self.check_injectivity(): break if self.n_jobs != 1: moving_images.apply_transforms_parallel( self.deformation.forward_mappings, self.n_jobs) fixed_images.apply_transforms_parallel( self.deformation.backward_mappings, self.n_jobs) else: moving_images.apply_transforms( self.deformation.forward_mappings) fixed_images.apply_transforms( self.deformation.backward_mappings) max_delta_phi = self.delta_phi * (max_iter - i) print "iteration%4d, Energy %f" % ( i + 1, self.similarity.cost(fixed_images[self.n_step_half], moving_images[self.n_step_half]) ) print 14 * ' ', "minimum unit", self.min_unit print 14 * ' ', "delta phi", self.delta_phi print 14 * ' ', "maximum delta phi", max_delta_phi if max_delta_phi < self.delta_phi_threshold / resolution: print "|L_inf norm of displacement| x iter < %f voxel" % ( self.delta_phi_threshold / resolution) break forward_mapping = self.zoom_grid( self.deformation.forward_mappings[self.n_step_half], resolution) backward_mapping = self.zoom_grid( self.deformation.backward_mappings[self.n_step_half], resolution) forward_mapping_inverse = self.zoom_grid( self.get_forward_mapping_inverse(), resolution) backward_mapping_inverse = self.zoom_grid( self.get_backward_mapping_inverse(), resolution) return (Deformation(grid=forward_mapping), Deformation(grid=backward_mapping), Deformation(grid=forward_mapping_inverse), Deformation(grid=backward_mapping_inverse))
class LDDMM(Registration): def set_vector_fields(self, shape): self.vector_fields = VectorFields(self.n_step, shape) def update(self, fixed, moving): if self.n_jobs != 1: self.update_parallel(fixed, moving) else: self.update_sequential(fixed, moving) def update_sequential(self, fixed, moving): for i in xrange(self.n_step + 1): j = - i - 1 momentum = (self.similarity.derivative(fixed[j], moving[i]) * self.deformation.backward_dets[j]) grad = 2 * self.vector_fields[i] + self.regularizer(momentum) delta = self.learning_rate * grad self.vector_fields.delta_vector_fields[i] = np.copy(delta) self.vector_fields.update() self.integrate_vector_fields() def update_parallel(self, fixed, moving): if hasattr(self.regularizer, "set_operator"): self.regularizer.set_operator(shape=fixed.shape) self.vector_fields.delta_vector_fields = np.array( Parallel(self.n_jobs)( delayed(derivative)(self.similarity, fixed[-i - 1], moving[i], self.deformation.backward_dets[-i - 1], self.vector_fields[i], self.regularizer, self.learning_rate) for i in xrange(self.n_step + 1) ) ) self.vector_fields.update() self.integrate_vector_fields() def integrate_vector_fields(self): v = 0.5 * (self.vector_fields[:-1] + self.vector_fields[1:]) forward_mapping_before = np.copy(self.deformation.forward_mappings[-1]) self.deformation.update_mappings(v) forward_mapping_after = np.copy(self.deformation.forward_mappings[-1]) self.delta_phi = np.max( np.abs(forward_mapping_after - forward_mapping_before)) def execute(self): warp = Deformation(shape=self.shape) for n_iter, resolution, sigma in zip(self.n_iters, self.resolutions, self.smoothing_sigmas): print "=======================================" print "resolution", resolution warped_moving = self.moving.apply_transform(warp) moving = warped_moving.change_resolution(resolution, sigma) fixed = self.fixed.change_resolution(resolution, sigma) shape = moving.get_shape() self.deformation.set_shape(shape) self.set_vector_fields(shape) grid = self.optimization(fixed, moving, n_iter, resolution) warp += Deformation(grid=grid) return warp def optimization(self, fixed, moving, max_iter, resolution): moving_images = SequentialScalarImages(moving, self.n_step + 1) fixed_images = SequentialScalarImages(fixed, self.n_step + 1) print "iteration 0, Energy %f" % ( self.similarity.cost(fixed.data, moving.data)) for i in xrange(max_iter): self.update(fixed_images, moving_images) if not self.check_injectivity(): break if self.n_jobs != 1: moving_images.apply_transforms_parallel( self.deformation.forward_mappings, self.n_jobs) fixed_images.apply_transforms_parallel( self.deformation.backward_mappings, self.n_jobs) else: moving_images.apply_transforms( self.deformation.forward_mappings) fixed_images.apply_transforms( self.deformation.backward_mappings) max_delta_phi = self.delta_phi * (max_iter - i) print "iteration%4d, Energy %f" % ( i + 1, self.similarity.cost(fixed_images[0], moving_images[-1])) print 14 * ' ', "minimum unit", self.min_unit print 14 * ' ', "delta phi", self.delta_phi print 14 * ' ', "maximum delta phi", max_delta_phi if max_delta_phi < self.delta_phi_threshold / resolution: print "|L_inf norm of displacement| x iter < %f voxel" % ( self.delta_phi_threshold / resolution) break return self.zoom_grid(self.deformation.forward_mappings[-1], resolution) def execute_coarse_to_fine(self): vector_fields = VectorFields(self.n_step, shape=self.shape) for n_iter, resolution, sigma in zip(self.n_iters, self.resolutions, self.smoothing_sigmas): print "=======================================" print "resolution", resolution fixed = self.fixed.change_resolution(resolution, sigma) moving = self.moving.change_resolution(resolution, sigma) shape = fixed.get_shape() self.vector_fields = vector_fields.change_resolution(resolution) self.deformation.set_shape(shape) v = 0.5 * (self.vector_fields[:-1] + self.vector_fields[1:]) self.deformation.update_mappings(v) vector_fields = self.optimization_coarse_to_fine( fixed, moving, n_iter, resolution) return self.deformation def optimization_coarse_to_fine(self, fixed, moving, max_iter, resolution): fixed_images = SequentialScalarImages(fixed, self.n_step) moving_images = SequentialScalarImages(moving, self.n_step) fixed_images.apply_transforms(self.deformation.backward_mappings) moving_images.apply_transforms(self.deformation.forward_mappings) print "iteration 0, Energy %f" % ( self.similarity.cost(fixed_images[0], moving_images[-1])) for i in xrange(max_iter): self.update(fixed_images, moving_images) if not self.check_injectivity(): break if self.n_jobs != 1: moving_images.apply_transforms_parallel( self.deformation.forward_mappings, self.n_jobs) fixed_images.apply_transforms_parallel( self.deformation.backward_mappings, self.n_jobs) else: moving_images.apply_transforms( self.deformation.forward_mappings) fixed_images.apply_transforms( self.deformation.backward_mappings) max_delta_phi = self.delta_phi * (max_iter - i) print "iteration%4d, Energy %f" % ( i + 1, self.similarity.cost(fixed_images[0], moving_images[-1])) print 14 * ' ', "minimum unit", self.min_unit print 14 * ' ', "delta phi", self.delta_phi print 14 * ' ', "maximum delta phi {0}".format(max_delta_phi) if max_delta_phi < self.delta_phi_threshold / resolution: print "|L_inf norm of displacement| x iter < %f voxel" % ( self.delta_phi_threshold / resolution) break return self.vector_fields.change_resolution(resolution=1. / resolution)
class LDDMM(Registration): def set_vector_fields(self, shape): self.vector_fields = VectorFields(self.n_step, shape) def update(self, fixed, moving): if self.n_jobs != 1: self.update_parallel(fixed, moving) else: self.update_sequential(fixed, moving) def update_sequential(self, fixed, moving): for i in xrange(self.n_step + 1): j = -i - 1 momentum = (self.similarity.derivative(fixed[j], moving[i]) * self.deformation.backward_dets[j]) grad = 2 * self.vector_fields[i] + self.regularizer(momentum) delta = self.learning_rate * grad self.vector_fields.delta_vector_fields[i] = np.copy(delta) self.vector_fields.update() self.integrate_vector_fields() def update_parallel(self, fixed, moving): if hasattr(self.regularizer, "set_operator"): self.regularizer.set_operator(shape=fixed.shape) self.vector_fields.delta_vector_fields = np.array( Parallel(self.n_jobs)(delayed(derivative)(self.similarity, fixed[ -i - 1], moving[i], self.deformation.backward_dets[ -i - 1], self.vector_fields[i], self.regularizer, self.learning_rate) for i in xrange(self.n_step + 1))) self.vector_fields.update() self.integrate_vector_fields() def integrate_vector_fields(self): v = 0.5 * (self.vector_fields[:-1] + self.vector_fields[1:]) forward_mapping_before = np.copy(self.deformation.forward_mappings[-1]) self.deformation.update_mappings(v) forward_mapping_after = np.copy(self.deformation.forward_mappings[-1]) self.delta_phi = np.max( np.abs(forward_mapping_after - forward_mapping_before)) def execute(self): warp = Deformation(shape=self.shape) for n_iter, resolution, sigma in zip(self.n_iters, self.resolutions, self.smoothing_sigmas): print "=======================================" print "resolution", resolution warped_moving = self.moving.apply_transform(warp) moving = warped_moving.change_resolution(resolution, sigma) fixed = self.fixed.change_resolution(resolution, sigma) shape = moving.get_shape() self.deformation.set_shape(shape) self.set_vector_fields(shape) grid = self.optimization(fixed, moving, n_iter, resolution) warp += Deformation(grid=grid) return warp def optimization(self, fixed, moving, max_iter, resolution): moving_images = SequentialScalarImages(moving, self.n_step + 1) fixed_images = SequentialScalarImages(fixed, self.n_step + 1) print "iteration 0, Energy %f" % (self.similarity.cost( fixed.data, moving.data)) for i in xrange(max_iter): self.update(fixed_images, moving_images) if not self.check_injectivity(): break if self.n_jobs != 1: moving_images.apply_transforms_parallel( self.deformation.forward_mappings, self.n_jobs) fixed_images.apply_transforms_parallel( self.deformation.backward_mappings, self.n_jobs) else: moving_images.apply_transforms( self.deformation.forward_mappings) fixed_images.apply_transforms( self.deformation.backward_mappings) max_delta_phi = self.delta_phi * (max_iter - i) print "iteration%4d, Energy %f" % ( i + 1, self.similarity.cost(fixed_images[0], moving_images[-1])) print 14 * ' ', "minimum unit", self.min_unit print 14 * ' ', "delta phi", self.delta_phi print 14 * ' ', "maximum delta phi", max_delta_phi if max_delta_phi < self.delta_phi_threshold / resolution: print "|L_inf norm of displacement| x iter < %f voxel" % ( self.delta_phi_threshold / resolution) break return self.zoom_grid(self.deformation.forward_mappings[-1], resolution) def execute_coarse_to_fine(self): vector_fields = VectorFields(self.n_step, shape=self.shape) for n_iter, resolution, sigma in zip(self.n_iters, self.resolutions, self.smoothing_sigmas): print "=======================================" print "resolution", resolution fixed = self.fixed.change_resolution(resolution, sigma) moving = self.moving.change_resolution(resolution, sigma) shape = fixed.get_shape() self.vector_fields = vector_fields.change_resolution(resolution) self.deformation.set_shape(shape) v = 0.5 * (self.vector_fields[:-1] + self.vector_fields[1:]) self.deformation.update_mappings(v) vector_fields = self.optimization_coarse_to_fine( fixed, moving, n_iter, resolution) return self.deformation def optimization_coarse_to_fine(self, fixed, moving, max_iter, resolution): fixed_images = SequentialScalarImages(fixed, self.n_step) moving_images = SequentialScalarImages(moving, self.n_step) fixed_images.apply_transforms(self.deformation.backward_mappings) moving_images.apply_transforms(self.deformation.forward_mappings) print "iteration 0, Energy %f" % (self.similarity.cost( fixed_images[0], moving_images[-1])) for i in xrange(max_iter): self.update(fixed_images, moving_images) if not self.check_injectivity(): break if self.n_jobs != 1: moving_images.apply_transforms_parallel( self.deformation.forward_mappings, self.n_jobs) fixed_images.apply_transforms_parallel( self.deformation.backward_mappings, self.n_jobs) else: moving_images.apply_transforms( self.deformation.forward_mappings) fixed_images.apply_transforms( self.deformation.backward_mappings) max_delta_phi = self.delta_phi * (max_iter - i) print "iteration%4d, Energy %f" % ( i + 1, self.similarity.cost(fixed_images[0], moving_images[-1])) print 14 * ' ', "minimum unit", self.min_unit print 14 * ' ', "delta phi", self.delta_phi print 14 * ' ', "maximum delta phi {0}".format(max_delta_phi) if max_delta_phi < self.delta_phi_threshold / resolution: print "|L_inf norm of displacement| x iter < %f voxel" % ( self.delta_phi_threshold / resolution) break return self.vector_fields.change_resolution(resolution=1. / resolution)