def __init__(self, source, target): super(CachedPWATransform, self).__init__(source, target) # make sure the source and target satisfy the c requirements source_c = np.require(self.source.points, dtype=np.float64, requirements=['C']) trilist_c = np.require(self.trilist, dtype=np.uint32, requirements=['C']) # build the cython wrapped C object and store it locally self._fastpwa = CLookupPWA(source_c, trilist_c) self.ti, self.tij, self.tik = None, None, None self._rebuild_target_vectors()
class CachedPWATransform(AbstractPWATransform): r""" A piecewise affine transformation. The apply method in this case involves dotting the triangle vectors with the values of alpha and beta found. The calculation of alpha and beta is done in C, and a hash map is used to cache lookup values. Parameters ---------- source : :class:`menpo.shape.PointCloud` or :class:`menpo.shape.TriMesh` The source points. If a TriMesh is provided, the triangulation on the TriMesh is used. If a :class:`menpo.shape.PointCloud` is provided, a Delaunay triangulation of the source is performed automatically. target : :class:`PointCloud` The target points. Note that the trilist is entirely decided by the source. Raises ------ ValueError Source and target must both be 2D. TriangleContainmentError All points to apply must be contained in a source triangle. Check ``error.points_outside_source_domain`` to handle this case. """ def __init__(self, source, target): super(CachedPWATransform, self).__init__(source, target) # make sure the source and target satisfy the c requirements source_c = np.require(self.source.points, dtype=np.float64, requirements=['C']) trilist_c = np.require(self.trilist, dtype=np.uint32, requirements=['C']) # build the cython wrapped C object and store it locally self._fastpwa = CLookupPWA(source_c, trilist_c) self.ti, self.tij, self.tik = None, None, None self._rebuild_target_vectors() def _rebuild_target_vectors(self): r""" Rebuild the vectors that are used in the apply method. This needs to be called whenever the target is changed. """ t = self.target.points[self.trilist] # get vectors ij ik for the target self.tij, self.tik = t[:, 1] - t[:, 0], t[:, 2] - t[:, 0] # target i'th vertex positions self.ti = t[:, 0] def index_alpha_beta(self, points): points_c = np.require(points, dtype=np.float64, requirements=['C']) index, alpha, beta = self._fastpwa.index_alpha_beta(points_c) if np.any(index < 0): raise TriangleContainmentError(index < 0) else: return index, alpha, beta def _apply(self, x, **kwargs): """ Applies this transform to a new set of vectors. Parameters ---------- x : (K, 2) ndarray Points to apply this transform to. Returns ------- transformed : (K, 2) ndarray The transformed array. """ tri_index, alpha, beta = self.index_alpha_beta(x) return (self.ti[tri_index] + alpha[:, None] * self.tij[tri_index] + beta[:, None] * self.tik[tri_index]) def _target_setter(self, new_target): r""" CachedPWATransform is particularly efficient to update from target - we don't have to do much at all, just rebuild the target vectors. """ self._target = new_target self._rebuild_target_vectors()