Source code for menpo.transform.base.alignment

import numpy as np

from menpo.base import Targetable
from menpo.visualize.base import Viewable


[docs]class Alignment(Targetable, Viewable): r""" Mix-in for :map:`Transform` that have been constructed from an optimisation aligning a source :map:`PointCloud` to a target :map:`PointCloud`. This is naturally an extension of the :map:`Targetable` interface - we just augment :map:`Targetable` with the concept of a source, and related methods to construct alignments between a source and a target. Note that to inherit from :map:`Alignment`, you have to be a :map:`Transform` subclass first. Parameters ---------- source : :map:`PointCloud` A PointCloud that the alignment will be based from target : :map:`PointCloud` A PointCloud that the alignment is targeted towards """ def __init__(self, source, target): self._verify_source_and_target(source, target) self._source = source self._target = target @staticmethod def _verify_source_and_target(source, target): r""" Checks that the dimensions and number of points match up of the source and the target. Parameters ---------- source : :map:`PointCloud` A PointCloud that the alignment will be based from target : :map:`PointCloud` A PointCloud that the alignment is targeted towards Raises ------ ValueError Source and target must have the same dimensionality ValueError Source and target must have the same number of points """ if source.n_dims != target.n_dims: raise ValueError("Source and target must have the same " "dimensionality") elif source.n_points != target.n_points: raise ValueError("Source and target must have the same number of" " points") @property def source(self): r""" The source :map:`PointCloud` that is used in the alignment. The source is not mutable. :type: :map:`PointCloud` """ return self._source
[docs] def aligned_source(self): r""" The result of applying ``self`` to :attr:`source` :type: :map:`PointCloud` """ # Note that here we have the dependency that we are a Transform return self.apply(self.source)
[docs] def alignment_error(self): r""" The Frobenius Norm of the difference between the target and the aligned source. :type: `float` """ return np.linalg.norm(self.target.points - self.aligned_source().points)
@property def target(self): r""" The current :map:`PointCloud` that this object produces. To change the target, use :meth:`set_target`. :type: :map:`PointCloud` """ return self._target def _target_setter(self, new_target): r""" Fulfils the :map:`Targetable` `_target_setter` interface for all Alignments. This method should purely set the target - we know how to do that for all :map:`Alignment` instances. Parameters ---------- new_target : :map:`PointCloud` The new PointCloud target """ self._target = new_target def _new_target_from_state(self): r""" Fulfils the :map:`Targetable` :meth:`_new_target_from_state` interface for all Alignments. This method should purely return the new target to be set - for all :map:`Alignment` instances this is just the aligned source. """ return self.aligned_source() def _view_2d(self, figure_id=None, new_figure=False, **kwargs): r""" Plots the source points and vectors that represent the shift from source to target. Parameters ---------- figure_id : `object`, optional The id of the figure to be used. new_figure : `bool`, optional If ``True``, a new figure is created. kwargs : `dict` The options passed to the rendered """ from menpo.visualize import AlignmentViewer2d return AlignmentViewer2d(figure_id, new_figure, self).render(**kwargs)