Beispiel #1
0
def test_obtain_shape_from_bb():
    fitter = LucasKanadeAAMFitter(aam)
    s = fitter.obtain_shape_from_bb(
        np.array([[53.916, 1.853], [408.469, 339.471]]))
    assert ((np.around(s.points) == np.around(initial_shape[0].points)).all())
    assert (s.n_dims == 2)
    assert (s.n_landmark_groups == 0)
    assert (s.n_points == 68)
Beispiel #2
0
def test_obtain_shape_from_bb():
    fitter = LucasKanadeAAMFitter(aam)
    s = fitter.obtain_shape_from_bb(np.array([[53.916, 1.853],
                                              [408.469, 339.471]]))
    assert ((np.around(s.points) == np.around(initial_shape[0].points)).all())
    assert (s.n_dims == 2)
    assert (s.n_landmark_groups == 0)
    assert (s.n_points == 68)
Beispiel #3
0
def aam_fit_benchmark(fitting_images, aam, fitting_options=None,
                      perturb_options=None, verbose=False):
    r"""
    Fits a trained AAM model to a database.

    Parameters
    ----------
    fitting_images: list of :class:MaskedImage objects
        A list of the fitting images.
    aam: :class:menpo.fitmultilevel.aam.AAM object
        The trained AAM object. It can be generated from the
        aam_build_benchmark() method.
    fitting_options: dictionary, optional
        A dictionary with the parameters that will be passed in the
        LucasKanadeAAMFitter (:class:menpo.fitmultilevel.aam.base).
        If None, the default options will be used.
        This is an example of the dictionary with the default options:
            fitting_options = {'algorithm': AlternatingInverseCompositional,
                               'md_transform': OrthoMDTransform,
                               'global_transform': AlignmentSimilarity,
                               'n_shape': None,
                               'n_appearance': None,
                               'max_iters': 50,
                               'error_type': 'me_norm'
                               }
        For an explanation of the options, please refer to the
        LucasKanadeAAMFitter documentation.

        Default: None
    bounding_boxes: list of (2, 2) ndarray, optional
        If provided, fits will be initialized from a bounding box. If
        None, perturbation of ground truth will be used instead.
        can be provided). Interpreted as [[min_x, min_y], [max_x, max_y]].
    perturb_options: dictionary, optional
        A dictionary with parameters that control the perturbation on the
        ground truth shape with noise of specified std. Note that if
        bounding_box is provided perturb_options is ignored and not used.
        If None, the default options will be used.
        This is an example of the dictionary with the default options:
            initialization_options = {'noise_std': 0.04,
                                      'rotation': False
                                      }
        For an explanation of the options, please refer to the perturb_shape()
        method documentation of :map:`MultilevelFitter`.
    verbose: bool, optional
        If True, it prints information regarding the AAM fitting including
        progress bar, current image error and percentage of images with errors
        less or equal than a value.

        Default: False

    Returns
    -------
    fitting_results: :map:`FittingResultList`
        A list with the :map:`FittingResult` object per image.
    """
    if verbose:
        print('AAM Fitting:')
        perc1 = 0.
        perc2 = 0.

    # parse options
    if fitting_options is None:
        fitting_options = {}
    if perturb_options is None:
        perturb_options = {}

    # extract some options
    group = fitting_options.pop('gt_group', 'PTS')
    max_iters = fitting_options.pop('max_iters', 50)
    error_type = fitting_options.pop('error_type', 'me_norm')

    # create fitter
    fitter = LucasKanadeAAMFitter(aam, **fitting_options)

    # fit images
    n_images = len(fitting_images)
    fitting_results = []
    for j, i in enumerate(fitting_images):
        # perturb shape
        gt_s = i.landmarks[group].lms
        if 'bbox' in i.landmarks:
            # shape from bounding box
            s = fitter.obtain_shape_from_bb(i.landmarks['bbox'].lms.points)
        else:
            # shape from perturbation
            s = fitter.perturb_shape(gt_s, **perturb_options)
        # fit
        fr = fitter.fit(i, s, gt_shape=gt_s, max_iters=max_iters)
        fitting_results.append(fr)

        # print
        final_error = fr.final_error(error_type=error_type)
        initial_error = fr.initial_error(error_type=error_type)
        if verbose:
            if error_type == 'me_norm':
                if final_error <= 0.03:
                    perc1 += 1.
                if final_error <= 0.04:
                    perc2 += 1.
            elif error_type == 'rmse':
                if final_error <= 0.05:
                    perc1 += 1.
                if final_error <= 0.06:
                    perc2 += 1.
            print_dynamic('- {0} - [<=0.03: {1:.1f}%, <=0.04: {2:.1f}%] - '
                          'Image {3}/{4} (error: {5:.3f} --> {6:.3f})'.format(
                progress_bar_str(float(j + 1) / n_images, show_bar=False),
                perc1 * 100. / n_images, perc2 * 100. / n_images, j + 1,
                n_images, initial_error, final_error))
    if verbose:
        print_dynamic('- Fitting completed: [<=0.03: {0:.1f}%, <=0.04: '
                      '{1:.1f}%]\n'.format(perc1 * 100. / n_images,
                                           perc2 * 100. / n_images))

    return fitting_results
Beispiel #4
0
def aam_fit_benchmark(fitting_images,
                      aam,
                      fitting_options=None,
                      perturb_options=None,
                      verbose=False):
    r"""
    Fits a trained AAM model to a database.

    Parameters
    ----------
    fitting_images: list of :class:MaskedImage objects
        A list of the fitting images.
    aam: :class:menpo.fitmultilevel.aam.AAM object
        The trained AAM object. It can be generated from the
        aam_build_benchmark() method.
    fitting_options: dictionary, optional
        A dictionary with the parameters that will be passed in the
        LucasKanadeAAMFitter (:class:menpo.fitmultilevel.aam.base).
        If None, the default options will be used.
        This is an example of the dictionary with the default options:
            fitting_options = {'algorithm': AlternatingInverseCompositional,
                               'md_transform': OrthoMDTransform,
                               'global_transform': AlignmentSimilarity,
                               'n_shape': None,
                               'n_appearance': None,
                               'max_iters': 50,
                               'error_type': 'me_norm'
                               }
        For an explanation of the options, please refer to the
        LucasKanadeAAMFitter documentation.

        Default: None
    bounding_boxes: list of (2, 2) ndarray, optional
        If provided, fits will be initialized from a bounding box. If
        None, perturbation of ground truth will be used instead.
        can be provided). Interpreted as [[min_x, min_y], [max_x, max_y]].
    perturb_options: dictionary, optional
        A dictionary with parameters that control the perturbation on the
        ground truth shape with noise of specified std. Note that if
        bounding_box is provided perturb_options is ignored and not used.
        If None, the default options will be used.
        This is an example of the dictionary with the default options:
            initialization_options = {'noise_std': 0.04,
                                      'rotation': False
                                      }
        For an explanation of the options, please refer to the perturb_shape()
        method documentation of :map:`MultilevelFitter`.
    verbose: bool, optional
        If True, it prints information regarding the AAM fitting including
        progress bar, current image error and percentage of images with errors
        less or equal than a value.

        Default: False

    Returns
    -------
    fitting_results: :map:`FittingResultList`
        A list with the :map:`FittingResult` object per image.
    """
    if verbose:
        print('AAM Fitting:')
        perc1 = 0.
        perc2 = 0.

    # parse options
    if fitting_options is None:
        fitting_options = {}
    if perturb_options is None:
        perturb_options = {}

    # extract some options
    group = fitting_options.pop('gt_group', 'PTS')
    max_iters = fitting_options.pop('max_iters', 50)
    error_type = fitting_options.pop('error_type', 'me_norm')

    # create fitter
    fitter = LucasKanadeAAMFitter(aam, **fitting_options)

    # fit images
    n_images = len(fitting_images)
    fitting_results = []
    for j, i in enumerate(fitting_images):
        # perturb shape
        gt_s = i.landmarks[group].lms
        if 'bbox' in i.landmarks:
            # shape from bounding box
            s = fitter.obtain_shape_from_bb(i.landmarks['bbox'].lms.points)
        else:
            # shape from perturbation
            s = fitter.perturb_shape(gt_s, **perturb_options)
        # fit
        fr = fitter.fit(i, s, gt_shape=gt_s, max_iters=max_iters)
        fitting_results.append(fr)

        # print
        final_error = fr.final_error(error_type=error_type)
        initial_error = fr.initial_error(error_type=error_type)
        if verbose:
            if error_type == 'me_norm':
                if final_error <= 0.03:
                    perc1 += 1.
                if final_error <= 0.04:
                    perc2 += 1.
            elif error_type == 'rmse':
                if final_error <= 0.05:
                    perc1 += 1.
                if final_error <= 0.06:
                    perc2 += 1.
            print_dynamic('- {0} - [<=0.03: {1:.1f}%, <=0.04: {2:.1f}%] - '
                          'Image {3}/{4} (error: {5:.3f} --> {6:.3f})'.format(
                              progress_bar_str(float(j + 1) / n_images,
                                               show_bar=False),
                              perc1 * 100. / n_images, perc2 * 100. / n_images,
                              j + 1, n_images, initial_error, final_error))
    if verbose:
        print_dynamic('- Fitting completed: [<=0.03: {0:.1f}%, <=0.04: '
                      '{1:.1f}%]\n'.format(perc1 * 100. / n_images,
                                           perc2 * 100. / n_images))

    return fitting_results