예제 #1
0
 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()
예제 #2
0
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()