def test_obtain_shape_from_bb(): fitter = LucasKanadeAAMFitter(aam) s = fitter.obtain_shape_from_bb(np.array([[26, 49], [350, 400]])) assert ((np.around(s.points) == np.around(initial_shape[3].points)).all()) assert (s.n_dims == 2) assert (s.n_landmark_groups == 0) assert (s.n_points == 68)
def test_obtain_shape_from_bb(): fitter = LucasKanadeAAMFitter(aam) s = fitter.obtain_shape_from_bb(np.array([[26, 49], [350, 400]])) assert ((np.around(s.points) == np.around(initial_shape[3].points)). all()) assert (s.n_dims == 2) assert (s.n_landmark_groups == 0) assert (s.n_points == 68)
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, error_type=error_type, verbose=False) fitting_results.append(fr) # print if verbose: if error_type == 'me_norm': if fr.final_error <= 0.03: perc1 += 1. if fr.final_error <= 0.04: perc2 += 1. elif error_type == 'rmse': if fr.final_error <= 0.05: perc1 += 1. if fr.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, fr.initial_error, fr.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)) # fit images fitting_results_list = FittingResultList(fitting_results) return fitting_results_list