Source code for menpo.base

import abc
from copy import deepcopy
import os.path


[docs]class Vectorizable(object): """Flattening of rich objects to vectors and rebuilding them back. Interface that provides methods for 'flattening' an object into a vector, and restoring from the same vectorized form. Useful for statistical analysis of objects, which commonly requires the data to be provided as a single vector. """ __metaclass__ = abc.ABCMeta @property
[docs] def n_parameters(self): r"""The length of the vector that this object produces. :type: `int` """ return (self.as_vector()).shape[0]
[docs] def as_vector(self, **kwargs): """ Returns a flattened representation of the object as a single vector. Returns ------- vector : (N,) ndarray The core representation of the object, flattened into a single vector. Note that this is always a view back on to the original object, but is not writable. """ v = self._as_vector(**kwargs) v.flags.writeable = False return v
@abc.abstractmethod def _as_vector(self, **kwargs): """ Returns a flattened representation of the object as a single vector. Returns ------- vector : ``(n_parameters,)`` `ndarray` The core representation of the object, flattened into a single vector. """ @abc.abstractmethod
[docs] def from_vector_inplace(self, vector): """Update the state of this object from a vector form. Parameters ---------- vector : ``(n_parameters,)`` `ndarray` Flattened representation of this object """
[docs] def from_vector(self, vector): """Build a new instance of the object from it's vectorized state. ``self`` is used to fill out the missing state required to rebuild a full object from it's standardized flattened state. This is the default implementation, which is which is a ``deepcopy`` of the object followed by a call to :meth:`from_vector_inplace()`. This method can be overridden for a performance benefit if desired. Parameters ---------- vector : ``(n_parameters,)`` `ndarray` Flattened representation of the object. Returns ------- object : ``type(self)`` An new instance of this class. """ self_copy = deepcopy(self) self_copy.from_vector_inplace(vector) return self_copy
[docs]class Targetable(object): """Interface for objects that can produce a :attr:`target` :map:`PointCloud`. This could for instance be the result of an alignment or a generation of a :map:`PointCloud` instance from a shape model. Implementations must define sensible behavior for: - what a target is: see :attr:`target` - how to set a target: see :meth:`set_target` - how to update the object after a target is set: see :meth:`_sync_state_from_target` - how to produce a new target after the changes: see :meth:`_new_target_from_state` Note that :meth:`_sync_target_from_state` needs to be triggered as appropriate by subclasses e.g. when :map:`from_vector_inplace` is called. This will in turn trigger :meth:`_new_target_from_state`, which each subclass must implement. """ __metaclass__ = abc.ABCMeta @property
[docs] def n_dims(self): r"""The number of dimensions of the :attr:`target`. :type: `int` """ return self.target.n_dims
@property
[docs] def n_points(self): r"""The number of points on the :attr:`target`. :type: `int` """ return self.target.n_points
@abc.abstractproperty
[docs] def target(self): r"""The current :map:`PointCloud` that this object produces. :type: :map:`PointCloud` """
[docs] def set_target(self, new_target): r"""Update this object so that it attempts to recreate the ``new_target``. Parameters ---------- new_target : :map:`PointCloud` The new target that this object should try and regenerate. """ self._target_setter_with_verification(new_target) # trigger the update self._sync_state_from_target() # and a sync
def _target_setter_with_verification(self, new_target): r"""Updates the target, checking it is sensible, without triggering a sync. Should be called by :meth:`_sync_target_from_state` once it has generated a suitable target representation. Parameters ---------- new_target : :map:`PointCloud` The new target that should be set. """ self._verify_target(new_target) self._target_setter(new_target) def _verify_target(self, new_target): r"""Performs sanity checks to ensure that the new target is valid. This includes checking the dimensionality matches and the number of points matches the current target's values. Parameters ---------- new_target : :map:`PointCloud` The target that needs to be verified. Raises ------ ValueError If the ``new_target`` has differing ``n_points`` or ``n_dims`` to ``self``. """ # If the target is None (i.e. on construction) then dodge the # verification if self.target is None: return if new_target.n_dims != self.target.n_dims: raise ValueError( "The current target is {}D, the new target is {}D - new " "target has to have the same dimensionality as the " "old".format(self.target.n_dims, new_target.n_dims)) elif new_target.n_points != self.target.n_points: raise ValueError( "The current target has {} points, the new target has {} " "- new target has to have the same number of points as the" " old".format(self.target.n_points, new_target.n_points)) @abc.abstractmethod def _target_setter(self, new_target): r"""Sets the target to the new value. Does no synchronization. Note that it is advisable that :meth:`_target_setter_with_verification` is called from subclasses instead of this. Parameters ---------- new_target : :map:`PointCloud` The new target that will be set. """ def _sync_target_from_state(self): new_target = self._new_target_from_state() self._target_setter_with_verification(new_target) @abc.abstractmethod def _new_target_from_state(self): r"""Generate a new target that is correct after changes to the object. Returns ------- object : ``type(self)`` """ pass @abc.abstractmethod def _sync_state_from_target(self): r"""Synchronizes the object state to be correct after changes to the target. Called automatically from the target setter. This is called after the target is updated - only handle synchronization here. """ pass
[docs]class DP(object): r"""Object that is able to take it's own derivative wrt parametrization. The parametrization of objects is typically defined by the :map:`Vectorizable` interface. As a result, :map:`DP` is a mix-in that should be inherited along with :map:`Vectorizable`. """ __metaclass__ = abc.ABCMeta @abc.abstractmethod
[docs] def d_dp(self, points): r"""The derivative of this spatial object wrt parametrization changes evaluated at points. Parameters ---------- points : ``(n_points, n_dims)`` `ndarray` The spatial points at which the derivative should be evaluated. Returns ------- d_dp : ``(n_points, n_parameters, n_dims)`` `ndarray` The jacobian wrt parametrization. ``d_dp[i, j, k]`` is the scalar differential change that the k'th dimension of the i'th point experiences due to a first order change in the j'th scalar in the parametrization vector. """
[docs]class DX(object): r"""Object that is able to take it's own derivative wrt spatial changes. """ __metaclass__ = abc.ABCMeta @abc.abstractmethod
[docs] def d_dx(self, points): r"""The first order derivative of this spatial object wrt spatial changes evaluated at points. Parameters ---------- points : ``(n_points, n_dims)`` `ndarray` The spatial points at which the derivative should be evaluated. Returns ------- d_dx : ``(n_points, n_dims, n_dims)`` `ndarray` The jacobian wrt spatial changes. ``d_dx[i, j, k]`` is the scalar differential change that the j'th dimension of the i'th point experiences due to a first order change in the k'th dimension. It may be the case that the jacobian is constant across space - in this case axis zero may have length ``1`` to allow for broadcasting. """
[docs]class DL(object): r"""Object that is able to take it's own derivative wrt landmark changes. """ __metaclass__ = abc.ABCMeta @abc.abstractmethod
[docs] def d_dl(self, points): r"""The derivative of this spatial object wrt spatial changes in anchor landmark points or centres, evaluated at points. Parameters ---------- points : ``(n_points, n_dims)`` `ndarray` The spatial points at which the derivative should be evaluated. Returns ------- d_dl : ``(n_points, n_centres, n_dims)`` `ndarray` The jacobian wrt landmark changes. ``d_dl[i, k, m]`` is the scalar differential change that the any dimension of the i'th point experiences due to a first order change in the m'th dimension of the k'th landmark point. Note that at present this assumes that the change in every dimension is equal. """
[docs]def menpo_src_dir_path(): r"""The path to the top of the menpo Python package. Useful for locating where the data folder is stored. Returns ------- path : str The full path to the top of the Menpo package """ return os.path.split(os.path.abspath(__file__))[0]