예제 #1
0
파일: base.py 프로젝트: ikassi/menpo
    def _instance(self, level, shape_instance, appearance_instance):
        template = self.appearance_models[level].mean
        landmarks = template.landmarks['source'].lms

        # build reference frame
        if self.patch_size:
            reference_frame = build_patch_reference_frame(
                shape_instance, patch_size=self.patch_size)
        else:
            if type(landmarks) == TriMesh:
                trilist = template.landmarks['source'].lms.trilist
            else:
                trilist = None
            reference_frame = build_reference_frame(
                shape_instance, trilist=trilist)

        transform = self.transform_cls(
            reference_frame.landmarks['source'].lms, landmarks)

        return appearance_instance.warp_to(reference_frame.mask, transform,
                                           self.interpolator)
예제 #2
0
파일: base.py 프로젝트: ikassi/menpo
def aam_builder(images, group=None, label='all', interpolator='scipy',
                diagonal_range=None, boundary=3,
                transform_cls=PiecewiseAffineTransform,
                trilist=None, patch_size=None, n_levels=3, downscale=2,
                scaled_reference_frames=False, feature_type=None,
                max_shape_components=None, max_appearance_components=None):

    r"""
    Builds an AAM object from a set of landmarked images.

    Parameters
    ----------
    images: list of :class:`menpo.image.Image`
        The set of landmarked images from which to build the AAM.

    group : string, Optional
        The key of the landmark set that should be used. If None,
        and if there is only one set of landmarks, this set will be used.

        Default: None

    label: string, Optional
        The label of of the landmark manager that you wish to use. If no
        label is passed, the convex hull of all landmarks is used.

        Default: 'all'

    interpolator:'scipy', Optional
        The interpolator that should be used to perform the warps.

        Default: 'scipy'

    diagonal_range: int, Optional
        All images will be rescaled to ensure that the scale of their
        landmarks matches the scale of the mean shape.

        If int, ensures that the mean shape is scaled so that
        the diagonal of the bounding box containing it matches the
        diagonal_range value.
        If None, the mean landmarks are not rescaled.

        Note that, because the reference frame is computed from the mean
        landmarks, this kwarg also specifies the diagonal length of the
        reference frame (provided that features computation does not change
        the image size).

        Default: None

    boundary: int, Optional
        The number of pixels to be left as a safe margin on the boundaries
        of the reference frame (has potential effects on the gradient
        computation).

        Default: 3

    transform_cls: :class:`menpo.transform.PureAlignmentTransform`, Optional
        The :class:`menpo.transform.PureAlignmentTransform` that will be
        used to warp the images.

        Default: :class:`menpo.transform.PiecewiseAffineTransform`

    trilist: (t, 3) ndarray, Optional
        Triangle list that will be used to build the reference frame. If None,
        defaults to performing Delaunay triangulation on the points.

        Default: None

        .. note::

            This kwarg will be completely ignored if the kwarg transform_cls
            is not set :class:`menpo.transform.PiecewiseAffineTransform` or
            if the kwarg patch_size is not set to None.

    patch_size: tuple of ints or None, Optional
        If tuple, the appearance model of the AAM will be obtained by
        sampling the appearance patches around the landmarks. If None, the
        standard representation for the AAMs' appearance model will be used
        instead.

        Default: None

        .. note::

            If tuple, the kwarg transform_cls will be automatically set to
            :class:`menpo.transform.TPS`.

    n_levels: int, Optional
        The number of multi-resolution pyramidal levels to be used.

        Default: 3

    downscale: float > 1, Optional
        The downscale factor that will be used to create the different AAM
        pyramidal levels.

        Default: 2

    scaled_reference_frames: boolean, Optional
        If False, the resolution of all reference frames used to build the
        appearance model will be fixed (the original images will be
        both smoothed and scaled using a Gaussian pyramid). Consequently, all
        appearance models will have the same dimensionality.
        If True, the reference frames used to create the appearance model
        will be themselves scaled (the original images will only be smoothed).
        Consequently, the dimensionality of all appearance models will be
        different.

        Default: False

    feature_type: string or closure, Optional
        If None, the appearance model will be build using the original image
        representation, i.e. no features will be extracted from the original
        images.
        If string or closure, the appearance model will be built from a
        feature representation of the original images:
            If string, the `ammbuilder` will try to compute image features by
            executing:

               feature_image = eval('img.feature_type.' + feature_type + '()')

            For this to work properly the feature_type needs to be one of
            Menpo's standard image feature methods. Note that, in this case,
            the feature computation will be carried out using the respective
            default options.

            Non-default feature options and new experimental features can be
            used by defining a closure. In this case, the closure must define a
            function that receives an image as input and returns a
            particular feature representation of that image. For example:

                def igo_double_from_std_normalized_intensities(image)
                    image = deepcopy(image)
                    image.normalize_std_inplace()
                    return image.feature_type.igo(double_angles=True)

            See `menpo.image.MaskedNDImage` for details more details on Menpo's
            standard image features and feature options.

        Default: None

    max_shape_components: 0 < int < n_components, Optional
        If int, it specifies the specific number of components of the
        original shape model to be retained.

        Default: None

    max_appearance_components: 0 < int < n_components, Optional
        If int, it specifies the specific number of components of the
        original appearance model to be retained.

        Default: None

    Returns
    -------
    aam : :class:`menpo.aam.AAM`
        The AAM object
    """

    if patch_size is not None:
        transform_cls = TPS

    print '- Rescaling images'
    shapes = [i.landmarks[group][label].lms for i in images]
    reference_shape = mean_pointcloud(shapes)
    if diagonal_range:
        x, y = reference_shape.range()
        scale = diagonal_range / np.sqrt(x**2 + y**2)
        Scale(scale, reference_shape.n_dims).apply_inplace(reference_shape)
    images = [i.rescale_to_reference_shape(reference_shape, group=group,
                                           label=label,
                                           interpolator=interpolator)
              for i in images]

    if scaled_reference_frames:
        print '- Setting gaussian smoothing generators'
        generator = [i.smoothing_pyramid(n_levels=n_levels,
                                         downscale=downscale)
                     for i in images]
    else:
        print '- Setting gaussian pyramid generators'
        generator = [i.gaussian_pyramid(n_levels=n_levels,
                                        downscale=downscale)
                     for i in images]

    print '- Building model pyramids'
    shape_models = []
    appearance_models = []
    # for each level
    for j in np.arange(n_levels):
        print ' - Level {}'.format(j)

        print '  - Computing feature_type'
        images = [compute_features(g.next(), feature_type) for g in generator]
        # extract potentially rescaled shapes
        shapes = [i.landmarks[group][label].lms for i in images]

        if scaled_reference_frames or j == 0:
            print '  - Building shape model'
            if j != 0:
                shapes = [Scale(1/downscale, n_dims=shapes[0].n_dims).apply(s)
                          for s in shapes]
            # centralize shapes
            centered_shapes = [Translation(-s.centre).apply(s) for s in shapes]
            # align centralized shape using Procrustes Analysis
            gpa = GeneralizedProcrustesAnalysis(centered_shapes)
            aligned_shapes = [s.aligned_source for s in gpa.transforms]

            # build shape model
            shape_model = PCAModel(aligned_shapes)
            if max_shape_components is not None:
                # trim shape model if required
                shape_model.trim_components(max_shape_components)

            print '  - Building reference frame'
            mean_shape = mean_pointcloud(aligned_shapes)
            if patch_size is not None:
                # build patch based reference frame
                reference_frame = build_patch_reference_frame(
                    mean_shape, boundary=boundary, patch_size=patch_size)
            else:
                # build reference frame
                reference_frame = build_reference_frame(
                    mean_shape, boundary=boundary, trilist=trilist)

        # add shape model to the list
        shape_models.append(shape_model)

        print '  - Computing transforms'
        transforms = [transform_cls(reference_frame.landmarks['source'].lms,
                                    i.landmarks[group][label].lms)
                      for i in images]

        print '  - Warping images'
        images = [i.warp_to(reference_frame.mask, t,
                            interpolator=interpolator)
                  for i, t in zip(images, transforms)]

        for i in images:
            i.landmarks['source'] = reference_frame.landmarks['source']
        if patch_size:
            for i in images:
                i.build_mask_around_landmarks(patch_size, group='source')
        else:
            for i in images:
                i.constrain_mask_to_landmarks(group='source', trilist=trilist)

        print '  - Building appearance model'
        appearance_model = PCAModel(images)
        # trim appearance model if required
        if max_appearance_components is not None:
            appearance_model.trim_components(max_appearance_components)

        # add appearance model to the list
        appearance_models.append(appearance_model)

    # reverse the list of shape and appearance models so that they are
    # ordered from lower to higher resolution
    shape_models.reverse()
    appearance_models.reverse()

    return AAM(shape_models, appearance_models, transform_cls, feature_type,
               reference_shape, downscale, patch_size, interpolator)