def test_basic_2d_similarity(): linear_component = np.array([[2, -6], [6, 2]]) translation_component = np.array([7, -8]) h_matrix = np.eye(3, 3) h_matrix[:-1, :-1] = linear_component h_matrix[:-1, -1] = translation_component similarity = Similarity(h_matrix) x = np.array([[0, 1], [1, 1], [-1, -5], [3, -5]]) # transform x explicitly solution = np.dot(x, linear_component.T) + translation_component # transform x using the affine transform result = similarity.apply(x) # check that both answers are equivalent assert_allclose(solution, result) # create several copies of x x_copies = np.array([x, x, x, x, x, x, x, x]) # transform all of copies at once using the affine transform results = similarity.apply(x_copies) # check that all copies have been transformed correctly for r in results: assert_allclose(solution, r)
def test_align_2d_similarity_set_h_matrix_raises_notimplemented_error(): linear_component = np.array([[2, -6], [6, 2]]) translation_component = np.array([7, -8]) h_matrix = np.eye(3, 3) h_matrix[:-1, :-1] = linear_component h_matrix[:-1, -1] = translation_component similarity = Similarity(h_matrix) source = PointCloud(np.array([[0, 1], [1, 1], [-1, -5], [3, -5]])) target = similarity.apply(source) # estimate the transform from source to source estimate = AlignmentSimilarity(source, source) # and set the target estimate.set_h_matrix(h_matrix)
def test_align_2d_similarity(): linear_component = np.array([[2, -6], [6, 2]]) translation_component = np.array([7, -8]) h_matrix = np.eye(3, 3) h_matrix[:-1, :-1] = linear_component h_matrix[:-1, -1] = translation_component similarity = Similarity(h_matrix) source = PointCloud(np.array([[0, 1], [1, 1], [-1, -5], [3, -5]])) target = similarity.apply(source) # estimate the transform from source and target estimate = AlignmentSimilarity(source, target) # check the estimates is correct assert_allclose(similarity.h_matrix, estimate.h_matrix)
def _recursive_procrustes(self): r""" Recursively calculates a procrustes alignment. """ from menpo.shape import mean_pointcloud from menpo.transform import Similarity if self.n_iterations > self.max_iterations: return False new_tgt = mean_pointcloud( [t.aligned_source.points for t in self.transforms]) # rescale the new_target to be the same size as the original about # it's centre rescale = Similarity.identity(new_tgt.n_dims) s = UniformScale(self.initial_target_scale / new_tgt.norm(), self.n_dims, skip_checks=True) t = Translation(-new_tgt.centre, skip_checks=True) rescale.compose_before_inplace(t) rescale.compose_before_inplace(s) rescale.compose_before_inplace(t.pseudoinverse) rescale.apply_inplace(new_tgt) # check to see if we have converged yet delta_target = np.linalg.norm(self.target.points - new_tgt.points) if delta_target < 1e-6: return True else: self.n_iterations += 1 for t in self.transforms: t.set_target(new_tgt) self.target = new_tgt return self._recursive_procrustes()
def test_similarity_jacobian_2d(): params = np.ones(4) t = Similarity.identity(2).from_vector(params) explicit_pixel_locations = np.array([[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2]]) dW_dp = t.jacobian(explicit_pixel_locations) assert_equal(dW_dp, sim_jac_solution2d)
def noisy_align(source, target, noise_std=0.04, rotation=False): r""" Constructs and perturbs the optimal similarity transform between source to the target by adding white noise to its weights. Parameters ---------- source: :class:`menpo.shape.PointCloud` The source pointcloud instance used in the alignment target: :class:`menpo.shape.PointCloud` The target pointcloud instance used in the alignment noise_std: float The standard deviation of the white noise Default: 0.04 rotation: boolean If False the second parameter of the Similarity, which captures captures inplane rotations, is set to 0. Default:False Returns ------- noisy_transform : :class: `menpo.transform.Similarity` The noisy Similarity Transform """ transform = AlignmentSimilarity(source, target, rotation=rotation) parameters = transform.as_vector() parameter_range = np.hstack((parameters[:2], target.range())) noise = (parameter_range * noise_std * np.random.randn(transform.n_parameters)) return Similarity.identity(source.n_dims).from_vector(parameters + noise)
def noisy_align(source, target, noise_std=0.04, rotation=False): r""" Constructs and perturbs the optimal similarity transform between source to the target by adding white noise to its weights. Parameters ---------- source: :class:`menpo.shape.PointCloud` The source pointcloud instance used in the alignment target: :class:`menpo.shape.PointCloud` The target pointcloud instance used in the alignment noise_std: float The standard deviation of the white noise Default: 0.04 rotation: boolean If False the second parameter of the Similarity, which captures captures inplane rotations, is set to 0. Default:False Returns ------- noisy_transform : :class: `menpo.transform.Similarity` The noisy Similarity Transform """ transform = AlignmentSimilarity(source, target, rotation=rotation) parameters = transform.as_vector() parameter_range = np.hstack((parameters[:2], target.range())) noise = (parameter_range * noise_std * np.random.randn(transform.n_parameters)) return Similarity.init_identity(source.n_dims).from_vector(parameters + noise)
def skew_shape(pointcloud, theta, phi): r""" Method that skews the provided pointcloud. Parameters ---------- pointcloud : `menpo.shape.PointCloud` The shape to distort. theta : `float` The skew angle over x axis (tan(theta)). phi : `float` The skew angle over y axis (tan(phi)). Returns ------- skewed_shape : `menpo.shape.PointCloud` The skewed (distorted) pointcloud. """ rotate_ccw = Similarity.init_identity(pointcloud.n_dims) # Create skew matrix h_matrix = np.ones((3, 3)) h_matrix[0, 1] = np.tan(theta * np.pi / 180.) h_matrix[1, 0] = np.tan(phi * np.pi / 180.) h_matrix[:2, 2] = 0. h_matrix[2, :2] = 0. r = Affine(h_matrix) t = Translation(-pointcloud.centre(), skip_checks=True) # Translate to origin, rotate counter-clockwise, then translate back rotate_ccw.compose_before_inplace(t) rotate_ccw.compose_before_inplace(r) rotate_ccw.compose_before_inplace(t.pseudoinverse()) return rotate_ccw.apply(pointcloud)
def _recursive_procrustes(self): r""" Recursively calculates a procrustes alignment. """ from menpo.shape import mean_pointcloud from menpo.transform import Similarity if self.n_iterations > self.max_iterations: return False new_tgt = mean_pointcloud([t.aligned_source.points for t in self.transforms]) # rescale the new_target to be the same size as the original about # it's centre rescale = Similarity.identity(new_tgt.n_dims) s = UniformScale(self.initial_target_scale / new_tgt.norm(), self.n_dims, skip_checks=True) t = Translation(-new_tgt.centre, skip_checks=True) rescale.compose_before_inplace(t) rescale.compose_before_inplace(s) rescale.compose_before_inplace(t.pseudoinverse) rescale.apply_inplace(new_tgt) # check to see if we have converged yet delta_target = np.linalg.norm(self.target.points - new_tgt.points) if delta_target < 1e-6: return True else: self.n_iterations += 1 for t in self.transforms: t.set_target(new_tgt) self.target = new_tgt return self._recursive_procrustes()
def test_similarity_2d_as_vector(): params = np.array([0.2, 0.1, 1.0, 2.0]) h**o = np.array([[params[0] + 1.0, -params[1], params[2]], [params[1], params[0] + 1.0, params[3]], [0.0, 0.0, 1.0]]) vec = Similarity(h**o).as_vector() assert_allclose(vec, params)
def test_similarity_2d_from_vector(): params = np.array([0.2, 0.1, 1, 2]) h**o = np.array([[params[0] + 1, -params[1], params[2]], [params[1], params[0] + 1, params[3]], [0, 0, 1]]) sim = Similarity.init_identity(2).from_vector(params) assert_almost_equal(sim.h_matrix, h**o)
def test_similarity_2d_from_vector(): params = np.array([0.2, 0.1, 1, 2]) h**o = np.array([[params[0] + 1, -params[1], params[2]], [params[1], params[0] + 1, params[3]], [0, 0, 1]]) sim = Similarity.init_identity(2).from_vector(params) assert_equal(sim.h_matrix, h**o)
def test_similarity_jacobian_2d(): params = np.ones(4) t = Similarity.identity(2).from_vector(params) explicit_pixel_locations = np.array( [[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2]]) dW_dp = t.d_dp(explicit_pixel_locations) assert_equal(dW_dp, sim_jac_solution2d)
def test_similarity_jacobian_3d_raises_dimensionalityerror(): t = Similarity(np.eye(4)) t.d_dp(np.ones([2, 3]))
def test_similarity_identity_3d(): assert_allclose(Similarity.init_identity(3).h_matrix, np.eye(4))
def test_similarity_2d_points_raises_dimensionalityerror(): params = np.ones(4) t = Similarity.identity(2).from_vector(params) t.d_dp(np.ones([2, 3]))
def test_similarity_2d_n_parameters(): h**o = np.eye(3) t = Similarity(h**o) assert(t.n_parameters == 4)
def test_similarity_identity_2d(): assert_allclose(Similarity.init_identity(2).h_matrix, np.eye(3))
def test_similarity_set_h_matrix_raises_notimplementederror(): s = Similarity(np.eye(3)) s.set_h_matrix(s.h_matrix)
def test_similarity_3d_n_parameters_raises_notimplementederror(): h**o = np.eye(4) t = Similarity(h**o) # Raises exception t.n_parameters
def test_similarity_identity_2d(): assert_allclose(Similarity.identity(2).h_matrix, np.eye(3))
def test_similarity_3d_n_parameters_raises_notimplementederror(): h**o = np.eye(4) t = Similarity(h**o) with raises(NotImplementedError): t.n_parameters
def test_similarity_identity_3d(): assert_allclose(Similarity.identity(3).h_matrix, np.eye(4))