Exemple #1
0
def detect(detector_callable, image, greyscale=True, image_diagonal=None, group_prefix="object", channels_at_back=True):
    r"""
    Apply the general detection framework.

    This involves converting the image to greyscale if necessary, rescaling
    the image to a given diagonal, performing the detection, and attaching
    the scaled landmarks back onto the original image.

    uint8 images cannot be converted to greyscale by this framework, so must
    already be greyscale or ``greyscale=False``.

    Parameters
    ----------
    detector_callable : `callable` or `function`
        A callable object that will perform detection given a single parameter,
        a `uint8` numpy array with either no channels, or channels as the
        *last* axis.
    image : `menpo.image.Image`
        A Menpo image to detect. The bounding boxes of the detected objects
        will be attached to this image.
    greyscale : `bool`, optional
        Convert the image to greyscale or not.
    image_diagonal : `int`, optional
        The total size of the diagonal of the image that should be used for
        detection. This is useful for scaling images up and down for detection.
    group_prefix : `str`, optional
        The prefix string to be appended to each each landmark group that is
        stored on the image. Each detection will be stored as group_prefix_#
        where # is a count starting from 0.
    channels_at_back : `bool`, optional
        If ``True``, the image channels are placed onto the last axis (the back)
        as is common in many imaging packages. This is contrary to the Menpo
        default where channels are the first axis (at the front).

    Returns
    -------
    bounding_boxes : `list` of `menpo.shape.PointDirectedGraph`
        A list of bounding boxes representing the detections found.
    """
    d_image = image

    if greyscale:
        d_image = _greyscale(d_image)

    if image_diagonal is not None:
        scale_factor = image_diagonal / image.diagonal()
        d_image = d_image.rescale(scale_factor)

    pcs = detector_callable(menpo_image_to_uint8(d_image, channels_at_back=channels_at_back))

    if image_diagonal is not None:
        s = UniformScale(1 / scale_factor, n_dims=2)
        pcs = [s.apply(pc) for pc in pcs]

    padding_magnitude = len(str(len(pcs)))
    for i, pc in enumerate(pcs):
        key = "{prefix}_{num:0{mag}d}".format(mag=padding_magnitude, prefix=group_prefix, num=i)
        image.landmarks[key] = pc
    return pcs
Exemple #2
0
def test_uniformscale_2d_pseudoinverse():
    scale = 0.5
    h**o = np.array([[scale, 0, 0],
                     [0, scale, 0],
                     [0, 0, 1]])

    tr = UniformScale(2, 2)
    assert_almost_equal(tr.pseudoinverse().h_matrix, h**o)
Exemple #3
0
def test_align_2d_uniform_scale():
    scale = UniformScale(2.5, 2)
    source = PointCloud(np.array([[0, 1], [1, 1], [-1, -5], [3, -5]]))
    target = scale.apply(source)
    # estimate the transform from source and target
    estimate = AlignmentUniformScale(source, target)
    # check the estimates is correct
    assert_allclose(scale.h_matrix, estimate.h_matrix)
Exemple #4
0
def test_uniformscale2d_update_from_vector():
    # make a uniform scale of 1, 2 dimensional
    uniform_scale = UniformScale(1, 2)
    new_scale = 2
    h**o = np.array([[new_scale, 0, 0], [0, new_scale, 0], [0, 0, 1]])

    uniform_scale._from_vector_inplace(new_scale)
    assert_equal(uniform_scale.h_matrix, h**o)
Exemple #5
0
def test_align_2d_uniform_scale_set_h_matrix_raises_notimplemented_error():
    scale = UniformScale(2.5, 2)
    source = PointCloud(np.array([[0, 1], [1, 1], [-1, -5], [3, -5]]))
    target = scale.apply(source)
    # estimate the transform from source and source
    estimate = AlignmentUniformScale(source, source)
    # and set the target
    estimate.set_h_matrix(scale.h_matrix)
Exemple #6
0
def test_uniformscale3d_from_vector():
    scale = 2
    h**o = np.array([[scale, 0, 0, 0], [0, scale, 0, 0], [0, 0, scale, 0],
                     [0, 0, 0, 1]])

    uniform_scale = UniformScale(1, 3)
    tr = uniform_scale.from_vector(scale)
    assert_equal(tr.h_matrix, h**o)
Exemple #7
0
def test_align_2d_uniform_scale_set_h_matrix_raises_notimplemented_error():
    scale = UniformScale(2.5, 2)
    source = PointCloud(np.array([[0, 1], [1, 1], [-1, -5], [3, -5]]))
    target = scale.apply(source)
    # estimate the transform from source and source
    estimate = AlignmentUniformScale(source, source)
    # and set the target
    estimate.set_h_matrix(scale.h_matrix)
Exemple #8
0
def test_align_2d_uniform_scale():
    scale = UniformScale(2.5, 2)
    source = PointCloud(np.array([[0, 1], [1, 1], [-1, -5], [3, -5]]))
    target = scale.apply(source)
    # estimate the transform from source and target
    estimate = AlignmentUniformScale(source, target)
    # check the estimates is correct
    assert_allclose(scale.h_matrix, estimate.h_matrix)
def homog_compose_before_alignment_nonuniformscale_test():
    homog = Homogeneous(np.array([[0, 1, 0], [1, 0, 0], [0, 0, 1]]))
    scale = UniformScale(2.5, 2)
    source = PointCloud(np.array([[0, 1], [1, 1], [-1, -5], [3, -5]]))
    target = scale.apply(source)
    # estimate the transform from source and target
    s = AlignmentUniformScale(source, target)
    res = homog.compose_before(s)
    assert (type(res) == Homogeneous)
def test_uniformscale3d_from_vector():
    scale = 2
    h**o = np.array([[scale, 0, 0, 0],
                     [0, scale, 0, 0],
                     [0, 0, scale, 0],
                     [0, 0, 0, 1]])

    uniform_scale = UniformScale(1, 3)
    tr = uniform_scale.from_vector(scale)
    assert_equal(tr.h_matrix, h**o)
def test_uniformscale2d_update_from_vector():
    # make a uniform scale of 1, 2 dimensional
    uniform_scale = UniformScale(1, 2)
    new_scale = 2
    h**o = np.array([[new_scale, 0, 0],
                     [0, new_scale, 0],
                     [0, 0, 1]])

    uniform_scale._from_vector_inplace(new_scale)
    assert_equal(uniform_scale.h_matrix, h**o)
def test_homog_compose_before_alignment_nonuniformscale():
    homog = Homogeneous(np.array([[0, 1, 0],
                                  [1, 0, 0],
                                  [0, 0, 1]]))
    scale = UniformScale(2.5, 2)
    source = PointCloud(np.array([[0, 1],
                                  [1, 1],
                                  [-1, -5],
                                  [3, -5]]))
    target = scale.apply(source)
    # estimate the transform from source and target
    s = AlignmentUniformScale(source, target)
    res = homog.compose_before(s)
    assert(type(res) == Homogeneous)
Exemple #13
0
    def _recursive_procrustes(self):
        r"""
        Recursively calculates a procrustes alignment.
        """
        from menpo.shape import mean_pointcloud
        from menpo.transform import Similarity
        if self.n_iterations > self.max_iterations:
            return False
        new_tgt = mean_pointcloud(
            [t.aligned_source.points for t in self.transforms])
        # rescale the new_target to be the same size as the original about
        # it's centre
        rescale = Similarity.identity(new_tgt.n_dims)

        s = UniformScale(self.initial_target_scale / new_tgt.norm(),
                         self.n_dims,
                         skip_checks=True)
        t = Translation(-new_tgt.centre, skip_checks=True)
        rescale.compose_before_inplace(t)
        rescale.compose_before_inplace(s)
        rescale.compose_before_inplace(t.pseudoinverse)
        rescale.apply_inplace(new_tgt)
        # check to see if we have converged yet
        delta_target = np.linalg.norm(self.target.points - new_tgt.points)
        if delta_target < 1e-6:
            return True
        else:
            self.n_iterations += 1
            for t in self.transforms:
                t.set_target(new_tgt)
            self.target = new_tgt
            return self._recursive_procrustes()
Exemple #14
0
 def _recursive_procrustes(self):
     """
     Recursively calculates a Procrustes alignment
     """
     if self.n_iterations > self.max_iterations:
         return False
     av_aligned_source = sum(t.aligned_source.points
                             for t in self.transforms) / self.n_sources
     new_target = PointCloud(av_aligned_source)
     # rescale the new_target to be the same size as the original about
     # it's centre
     rescale = UniformScale(self.initial_target_scale / new_target.norm(),
                            self.n_dims)
     centre = Translation(-new_target.centre)
     rescale_about_centre = centre.compose_before(rescale).compose_before(
         centre.pseudoinverse)
     rescale_about_centre.apply_inplace(new_target)
     # check to see if  we have converged yet
     delta_target = np.linalg.norm(self.target.points - new_target.points)
     if delta_target < 1e-6:
         return True
     else:
         self.n_iterations += 1
         for t in self.transforms:
             t.set_target(new_target)
         self.target = new_target
         return self._recursive_procrustes()
Exemple #15
0
def test_uniformscale_build_2d():
    scale = 2
    h**o = np.array([[scale, 0, 0],
                     [0, scale, 0],
                     [0, 0, 1]])

    tr = UniformScale(scale, 2)
    assert_equal(tr.h_matrix, h**o)
Exemple #16
0
def detect(detector_callable,
           image,
           greyscale=True,
           image_diagonal=None,
           group_prefix='object'):
    r"""
    Apply the general detection framework.

    This involves converting the image to greyscale if necessary, rescaling
    the image to a given diagonal, performing the detection, and attaching
    the scaled landmarks back onto the original image.

    Parameters
    ----------
    detector_callable : callable or function
        A callable object that will perform detection given a single parameter,
        a uint8 numpy array.
    image : menpo.image.Image
        A Menpo image to detect. The bounding boxes of the detected objects
        will be attached to this image.
    greyscale : bool, optional
        Convert the image to greyscale or not.
    image_diagonal : int, optional
        The total size of the diagonal of the image that should be used for
        detection. This is useful for scaling images up and down for detection.
    group_prefix : str, optional
        The prefix string to be appended to each each landmark group that is
        stored on the image. Each detection will be stored as group_prefix_#
        where # is a count starting from 0.

    Returns
    -------
    bounding_boxes : menpo.shape.PointDirectedGraph
        A list of bounding boxes representing the detections found.
    """
    d_image = image

    if greyscale:
        d_image = _greyscale(d_image)

    if image_diagonal is not None:
        scale_factor = image_diagonal / image.diagonal
        d_image = d_image.rescale(scale_factor)

    pcs = detector_callable(menpo_image_to_uint8(d_image))

    if image_diagonal is not None:
        pcs = [
            UniformScale(1 / scale_factor, n_dims=2).apply(pc) for pc in pcs
        ]

    padding_magnitude = len(str(len(pcs)))
    for i, pc in enumerate(pcs):
        key = '{prefix}_{num:0{mag}d}'.format(mag=padding_magnitude,
                                              prefix=group_prefix,
                                              num=i)
        image.landmarks[key] = pc
    return pcs
Exemple #17
0
def test_uniformscale_build_3d():
    scale = 2
    h**o = np.array([[scale, 0, 0, 0], [0, scale, 0, 0], [0, 0, scale, 0],
                     [0, 0, 0, 1]])

    tr = UniformScale(scale, 3)

    assert (isinstance(tr, UniformScale))
    assert_equal(tr.h_matrix, h**o)
Exemple #18
0
def test_homog_compose_after_uniformscale():
    homog = Homogeneous(np.array([[0, 1, 0],
                                  [1, 0, 0],
                                  [0, 0, 1]]))
    s = UniformScale(3, 2)
    res = homog.compose_after(s)
    assert(type(res) == Homogeneous)
    assert_allclose(res.h_matrix, np.array([[0, 3, 0],
                                            [3, 0, 0],
                                            [0, 0, 1]]))
Exemple #19
0
    def instance(self,
                 model_type='bfm',
                 alpha=None,
                 beta=None,
                 landmark_group='ibug68'):
        if alpha is None:
            alpha = np.zeros(len(self.shape_model.eigenvalues))
        if beta is None:
            beta = np.zeros(len(self.texture_model.eigenvalues))

        # Generate instance
        shape = self.shape_model.instance(alpha, normalized_weights=True)
        texture = self.texture_model.instance(beta, normalized_weights=True)

        if model_type == 'bfm':
            tex_scale = UniformScale(1. / 255, 3)
            lms_scale = UniformScale(1e-5, 3)
            texture = tex_scale.apply(texture.reshape([-1, 3]))
            landmarks = lms_scale.apply(self.landmarks)
        elif model_type == 'lsfm':
            pass

        trimesh = ColouredTriMesh(shape.points,
                                  trilist=shape.trilist,
                                  colours=texture)

        trimesh.landmarks[landmark_group] = landmarks

        return trimesh
Exemple #20
0
def test_align_2d_affine_compose_target():
    source = PointCloud(np.array([[0, 1], [1, 1], [-1, -5], [3, -5]]))
    target = UniformScale(2.0, n_dims=2).apply(source)
    original_estimate = AlignmentAffine(source, target)
    new_estimate = original_estimate.copy()
    new_estimate.compose_after_from_vector_inplace(
        np.array([0, 0, 0, 0, 1, 1.]))
    estimate_target = new_estimate.target

    correct_target = original_estimate.compose_after(Translation(
        [1, 1.])).apply(source)

    assert_allclose(estimate_target.points, correct_target.points)
def test_transform_about_centre(method):
    pixels_16 = np.arange(16, dtype=np.float)
    image = Image(pixels_16.reshape(4, 4))
    transform = Rotation.init_from_2d_ccw_angle(180).compose_before(
        UniformScale(2, n_dims=2)
    )
    # rotate 180 + scale degrees
    transformed_img = image.transform_about_centre(transform, mode="nearest", order=1)
    expected_pixels = np.concatenate(
        [np.linspace(15 - 2 * i, 12 - 2 * i, num=7)[None] for i in range(7)]
    )

    assert transformed_img.shape == (7, 7)
    assert_allclose(transformed_img.pixels[0], expected_pixels, rtol=1e-8, atol=1e-8)
Exemple #22
0
def test_transform_about_centre():
    pixels_16 = np.arange(16, dtype=np.float)
    image = Image(pixels_16.reshape(4, 4))
    transform = Rotation.init_from_2d_ccw_angle(180).compose_before(
        UniformScale(2, n_dims=2))
    # rotate 90 + scale degrees
    transformed_img = image.transform_about_centre(transform, order=0)
    expected_pixels = np.rot90(np.repeat(np.repeat(pixels_16,
                                                   2).reshape(4, -1),
                                         2,
                                         axis=0)[1:, 1:],
                               k=2)

    assert transformed_img.shape == (7, 7)
    assert_allclose(transformed_img.pixels[0], expected_pixels)
Exemple #23
0
def rescale(mesh, center, var):
    """
    Rescale mesh according to given variances.

    Parameters:
        mesh (menpo.shape.mesh.base.TriMesh): mesh to be rescaled
        center (numpy.array of 3 floats): center on 3 dimensions
        var (numpy.array of 3 floats): variance on 3 dimensions

    Returns:
        mesh (menpo.shape.mesh.base.TriMesh): rescaled source
    """
    tr = Translation(center)
    sc = UniformScale(np.mean(var / mesh.range()), 3)
    prepare = tr.compose_after(sc)

    return prepare.apply(mesh)
Exemple #24
0
def test_uniformscale_set_h_matrix_raises_notimplementederror():
    s = UniformScale(2, 3)
    s.set_h_matrix(s.h_matrix)
Exemple #25
0
def test_uniformscale_identity_2d():
    assert_allclose(UniformScale.identity(2).h_matrix, np.eye(3))
Exemple #26
0
def test_uniformscale3d_n_parameters():
    scale = 2
    t = UniformScale(scale, 3)
    assert(t.n_parameters == 1)
Exemple #27
0
def test_translation_compose_after_uniformscale():
    t = Translation([3, 4])
    s = UniformScale(2, 2)
    res = t.compose_after(s)
    assert(type(res) == Similarity)
def test_uniformscale_compose_after_translation():
    t = Translation([3, 4])
    s = UniformScale(2, 2)
    res = s.compose_after(t)
    assert(type(res) == Similarity)
Exemple #29
0
def mesh_in_unit_sphere(mesh):
    scale = UniformScale(1 / mesh.norm(), mesh.n_dims)
    translation = Translation(-scale.apply(mesh).centre())
    return translation.compose_after(scale)
Exemple #30
0
def non_rigid_icp_generator(
    source,
    target,
    eps=1e-3,
    stiffness_weights=None,
    data_weights=None,
    landmark_group=None,
    landmark_weights=None,
    v_i_update_func=None,
    verbose=False,
):
    r"""
    Deforms the source trimesh to align with to optimally the target.
    """
    # If landmarks are provided, we should always start with a simple
    # AlignmentSimilarity between the landmarks to initialize optimally.
    if landmark_group is not None:
        if verbose:
            print("'{}' landmarks will be used as "
                  "a landmark constraint.".format(landmark_group))
            print("performing similarity alignment using landmarks")
        lm_align = AlignmentSimilarity(
            source.landmarks[landmark_group],
            target.landmarks[landmark_group]).as_non_alignment()
        source = lm_align.apply(source)

    # Scale factors completely change the behavior of the algorithm - always
    # rescale the source down to a sensible size (so it fits inside box of
    # diagonal 1) and is centred on the origin. We'll undo this after the fit
    # so the user can use whatever scale they prefer.
    tr = Translation(-1 * source.centre())
    sc = UniformScale(1.0 / np.sqrt(np.sum(source.range()**2)), 3)
    prepare = tr.compose_before(sc)

    source = prepare.apply(source)
    target = prepare.apply(target)

    # store how to undo the similarity transform
    restore = prepare.pseudoinverse()

    n_dims = source.n_dims
    # Homogeneous dimension (1 extra for translation effects)
    h_dims = n_dims + 1
    points, trilist = source.points, source.trilist
    n = points.shape[0]  # record number of points

    edge_tris = source.boundary_tri_index()

    M_s, unique_edge_pairs = node_arc_incidence_matrix(source)

    # weight matrix
    G = np.identity(n_dims + 1)

    M_kron_G_s = sp.kron(M_s, G)

    # build octree for finding closest points on target.
    target_vtk = trimesh_to_vtk(target)
    closest_points_on_target = VTKClosestPointLocator(target_vtk)

    # save out the target normals. We need them for the weight matrix.
    target_tri_normals = target.tri_normals()

    # init transformation
    X_prev = np.tile(np.zeros((n_dims, h_dims)), n).T
    v_i = points

    if stiffness_weights is not None:
        if verbose:
            print("using user-defined stiffness_weights")
        validate_weights("stiffness_weights",
                         stiffness_weights,
                         source.n_points,
                         verbose=verbose)
    else:
        # these values have been empirically found to perform well for well
        # rigidly aligned facial meshes
        stiffness_weights = [50, 20, 5, 2, 0.8, 0.5, 0.35, 0.2]
        if verbose:
            print("using default "
                  "stiffness_weights: {}".format(stiffness_weights))

    n_iterations = len(stiffness_weights)

    if landmark_weights is not None:
        if verbose:
            print("using user defined "
                  "landmark_weights: {}".format(landmark_weights))
    elif landmark_group is not None:
        # these values have been empirically found to perform well for well
        # rigidly aligned facial meshes
        landmark_weights = [5, 2, 0.5, 0, 0, 0, 0, 0]
        if verbose:
            print("using default "
                  "landmark_weights: {}".format(landmark_weights))
    else:
        # no landmark_weights provided - no landmark_group in use. We still
        # need a landmark group for the iterator
        landmark_weights = [None] * n_iterations

    # We should definitely have some landmark weights set now - check the
    # number is correct.
    # Note we say verbose=False, as we have done custom reporting above, and
    # per-vertex landmarks are not supported.
    validate_weights(
        "landmark_weights",
        landmark_weights,
        source.n_points,
        n_iterations=n_iterations,
        verbose=False,
    )

    if data_weights is not None:
        if verbose:
            print("using user-defined data_weights")
        validate_weights(
            "data_weights",
            data_weights,
            source.n_points,
            n_iterations=n_iterations,
            verbose=verbose,
        )
    else:
        data_weights = [None] * n_iterations
        if verbose:
            print("Not customising data_weights")

    # we need to prepare some indices for efficient construction of the D
    # sparse matrix.
    row = np.hstack((np.repeat(np.arange(n)[:, None], n_dims,
                               axis=1).ravel(), np.arange(n)))

    x = np.arange(n * h_dims).reshape((n, h_dims))
    col = np.hstack((x[:, :n_dims].ravel(), x[:, n_dims]))
    o = np.ones(n)

    if landmark_group is not None:
        source_lm_index = source.distance_to(
            source.landmarks[landmark_group]).argmin(axis=0)
        target_lms = target.landmarks[landmark_group]
        U_L = target_lms.points
        n_landmarks = target_lms.n_points
        lm_mask = np.in1d(row, source_lm_index)
        col_lm = col[lm_mask]
        # pull out the rows for the lms - but the values are
        # all wrong! need to map them back to the order of the landmarks
        row_lm_to_fix = row[lm_mask]
        source_lm_index_l = list(source_lm_index)
        row_lm = np.array([source_lm_index_l.index(r) for r in row_lm_to_fix])

    for i, (alpha, beta, gamma) in enumerate(
            zip(stiffness_weights, landmark_weights, data_weights), 1):
        alpha_is_per_vertex = isinstance(alpha, np.ndarray)
        if alpha_is_per_vertex:
            # stiffness is provided per-vertex
            if alpha.shape[0] != source.n_points:
                raise ValueError()
            alpha_per_edge = alpha[unique_edge_pairs].mean(axis=1)
            alpha_M_s = sp.diags(alpha_per_edge).dot(M_s)
            alpha_M_kron_G_s = sp.kron(alpha_M_s, G)
        else:
            # stiffness is global - just a scalar multiply. Note that here
            # we don't have to recalculate M_kron_G_s
            alpha_M_kron_G_s = alpha * M_kron_G_s

        if verbose:
            a_str = (alpha if not alpha_is_per_vertex
                     else "min: {:.2f}, max: {:.2f}".format(
                         alpha.min(), alpha.max()))
            i_str = "{}/{}: stiffness: {}".format(i, len(stiffness_weights),
                                                  a_str)
            if landmark_group is not None:
                i_str += "  lm_weight: {}".format(beta)
            print(i_str)

        j = 0
        while True:  # iterate until convergence
            j += 1  # track the iterations for this alpha/landmark weight

            # find nearest neighbour and the normals
            U, tri_indices = closest_points_on_target(v_i)

            # ---- WEIGHTS ----
            # 1.  Edges
            # Are any of the corresponding tris on the edge of the target?
            # Where they are we return a false weight (we *don't* want to
            # include these points in the solve)
            w_i_e = np.in1d(tri_indices, edge_tris, invert=True)

            # 2. Normals
            # Calculate the normals of the current v_i
            v_i_tm = TriMesh(v_i, trilist=trilist, copy=False)
            v_i_n = v_i_tm.vertex_normals()
            # Extract the corresponding normals from the target
            u_i_n = target_tri_normals[tri_indices]
            # If the dot of the normals is lt 0.9 don't contrib to deformation
            w_i_n = (u_i_n * v_i_n).sum(axis=1) > 0.9

            # 3. Self-intersection
            # This adds approximately 12% to the running cost and doesn't seem
            # to be very critical in helping mesh fitting performance so for
            # now it's removed. Revisit later.
            # # Build an intersector for the current deformed target
            # intersect = build_intersector(to_vtk(v_i_tm))
            # # budge the source points 1% closer to the target
            # source = v_i + ((U - v_i) * 0.5)
            # # if the vector from source to target intersects the deformed
            # # template we don't want to include it in the optimisation.
            # problematic = [i for i, (s, t) in enumerate(zip(source, U))
            #                if len(intersect(s, t)[0]) > 0]
            # print(len(problematic) * 1.0 / n)
            # w_i_i = np.ones(v_i_tm.n_points, dtype=np.bool)
            # w_i_i[problematic] = False

            # Form the overall w_i from the normals, edge case
            # for now disable the edge constraint (it was noisy anyway)
            w_i = w_i_n

            # w_i = np.logical_and(w_i_n, w_i_e).astype(np.float)

            # we could add self intersection at a later date too...
            # w_i = np.logical_and(np.logical_and(w_i_n,
            #                                     w_i_e,
            #                                     w_i_i).astype(np.float)

            prop_w_i = (n - w_i.sum() * 1.0) / n
            prop_w_i_n = (n - w_i_n.sum() * 1.0) / n
            prop_w_i_e = (n - w_i_e.sum() * 1.0) / n

            if gamma is not None:
                w_i = w_i * gamma

            # Build the sparse diagonal weight matrix
            W_s = sp.diags(w_i.astype(np.float)[None, :], [0])

            data = np.hstack((v_i.ravel(), o))
            D_s = sp.coo_matrix((data, (row, col)))

            to_stack_A = [alpha_M_kron_G_s, W_s.dot(D_s)]
            to_stack_B = [
                np.zeros((alpha_M_kron_G_s.shape[0], n_dims)),
                U * w_i[:, None],
            ]  # nullify nearest points by w_i

            if landmark_group is not None:
                D_L = sp.coo_matrix((data[lm_mask], (row_lm, col_lm)),
                                    shape=(n_landmarks, D_s.shape[1]))
                to_stack_A.append(beta * D_L)
                to_stack_B.append(beta * U_L)

            A_s = sp.vstack(to_stack_A).tocsr()
            B_s = sp.vstack(to_stack_B).tocsr()
            X = spsolve(A_s, B_s)

            # deform template
            v_i_prev = v_i
            v_i = D_s.dot(X)
            delta_v_i = v_i - v_i_prev

            if v_i_update_func:
                # custom logic is provided to update the current template
                # deformation. This is typically used by Active NICP.

                # take the v_i points matrix and convert back to a TriMesh in
                # the original space
                def_template = restore.apply(source.from_vector(v_i.ravel()))

                # perform the update
                updated_def_template = v_i_update_func(def_template)

                # convert back to points in the NICP space
                v_i = prepare.apply(updated_def_template.points)

            err = np.linalg.norm(X_prev - X, ord="fro")
            stop_criterion = err / np.sqrt(np.size(X_prev))

            if landmark_group is not None:
                src_lms = v_i[source_lm_index]
                lm_err = np.sqrt((src_lms - U_L)**2).sum(axis=1).mean()

            if verbose:
                v_str = (" - {} stop crit: {:.3f}  "
                         "total: {:.0%}  norms: {:.0%}  "
                         "edges: {:.0%}".format(j, stop_criterion, prop_w_i,
                                                prop_w_i_n, prop_w_i_e))
                if landmark_group is not None:
                    v_str += "  lm_err: {:.4f}".format(lm_err)

                print(v_str)

            X_prev = X

            # track the progress of the algorithm per-iteration
            info_dict = {
                "alpha": alpha,
                "iteration": j,
                "prop_omitted": prop_w_i,
                "prop_omitted_norms": prop_w_i_n,
                "prop_omitted_edges": prop_w_i_e,
                "delta": err,
                "mask_normals": w_i_n,
                "mask_edges": w_i_e,
                "mask_all": w_i,
                "nearest_points": restore.apply(U),
                "deformation_per_step": delta_v_i,
            }

            current_instance = source.copy()
            current_instance.points = v_i.copy()

            if landmark_group:
                info_dict["beta"] = beta
                info_dict["lm_err"] = lm_err
                current_instance.landmarks[landmark_group] = PointCloud(
                    src_lms)

            yield restore.apply(current_instance), info_dict

            if stop_criterion < eps:
                break
Exemple #31
0
def test_uniformscale_set_h_matrix_raises_notimplementederror():
    s = UniformScale(2, 3)
    s.set_h_matrix(s.h_matrix)
Exemple #32
0
def test_uniformscale_build_4d_raise_dimensionalityerror():
    UniformScale(1, 4)
Exemple #33
0
    def gaussian_pyramid(self,
                         n_levels=3,
                         downscale=2,
                         sigma=None,
                         order=1,
                         mode='reflect',
                         cval=0):
        r"""
        Return the gaussian pyramid of this image. The first image of the
        pyramid will be the original, unmodified, image.

        Parameters
        ----------
        n_levels : int
            Number of levels in the pyramid. When set to -1 the maximum
            number of levels will be build.

            Default: 3

        downscale : float, optional
            Downscale factor.

            Default: 2

        sigma : float, optional
            Sigma for gaussian filter. Default is `2 * downscale / 6.0` which
            corresponds to a filter mask twice the size of the scale factor
            that covers more than 99% of the gaussian distribution.

            Default: None

        order : int, optional
            Order of splines used in interpolation of downsampling. See
            `scipy.ndimage.map_coordinates` for detail.

            Default: 1

        mode :  {'reflect', 'constant', 'nearest', 'mirror', 'wrap'}, optional
            The mode parameter determines how the array borders are handled,
            where cval is the value when mode is equal to 'constant'.

            Default: 'reflect'

        cval : float, optional
            Value to fill past edges of input if mode is 'constant'.

            Default: 0

        Returns
        -------
        image_pyramid:
            Generator yielding pyramid layers as menpo image objects.
        """
        max_layer = n_levels - 1
        pyramid = pyramid_gaussian(self.pixels,
                                   max_layer=max_layer,
                                   downscale=downscale,
                                   sigma=sigma,
                                   order=order,
                                   mode=mode,
                                   cval=cval)

        for j, image_data in enumerate(pyramid):
            image = self.__class__(image_data)

            # rescale and reassign existent landmark
            image.landmarks = self.landmarks
            transform = UniformScale(downscale**j, self.n_dims)
            transform.pseudoinverse.apply_inplace(image.landmarks)
            yield image
Exemple #34
0
def test_uniformscale_identity_2d():
    assert_allclose(UniformScale.identity(2).h_matrix, np.eye(3))
Exemple #35
0
def test_uniformscale3d_as_vector():
    scale = 2
    vec = UniformScale(scale, 3).as_vector()
    assert_allclose(vec, scale)
Exemple #36
0
def test_uniformscale_identity_3d():
    assert_allclose(UniformScale.init_identity(3).h_matrix, np.eye(4))
Exemple #37
0
def test_uniformscale_build_4d_raise_dimensionalityerror():
    with raises(ValueError):
        UniformScale(1, 4)
Exemple #38
0
def test_uniformscale_identity_3d():
    assert_allclose(UniformScale.init_identity(3).h_matrix, np.eye(4))
Exemple #39
0
def test_warp_to_mask_preserves_path():
    bb = menpo.io.import_builtin_asset.breakingbad_jpg()
    no_op = UniformScale(1.0, n_dims=2)
    bb2 = bb.warp_to_mask(BooleanImage.init_blank((10, 10)), no_op)
    assert hasattr(bb2, "path")
    assert bb2.path == bb.path
Exemple #40
0
def render_patches(
        patches, patch_centers, patches_indices, offset_index, renderer,
        background, render_patches, channels, glyph_enabled, glyph_block_size,
        glyph_use_negative, sum_enabled, interpolation, cmap_name, alpha,
        render_patches_bboxes, bboxes_line_colour, bboxes_line_style,
        bboxes_line_width, render_centers, render_lines, line_colour,
        line_style, line_width, render_markers, marker_style, marker_size,
        marker_face_colour, marker_edge_colour, marker_edge_width,
        render_numbering, numbers_horizontal_align, numbers_vertical_align,
        numbers_font_name, numbers_font_size, numbers_font_style,
        numbers_font_weight, numbers_font_colour, render_axes, axes_font_name,
        axes_font_size, axes_font_style, axes_font_weight, axes_x_limits,
        axes_y_limits, axes_x_ticks, axes_y_ticks, figure_size):
    from menpo.transform import UniformScale
    from menpo.visualize import view_patches

    if glyph_enabled and render_patches:
        # compute glyph size
        glyph_patch0 = glyph(patches[0, offset_index, ...],
                             vectors_block_size=glyph_block_size,
                             use_negative=glyph_use_negative)
        # compute glyph of each patch
        glyph_patches = np.zeros(
            (patches.shape[0], 1, 1, glyph_patch0.shape[1],
             glyph_patch0.shape[2]))
        glyph_patches[0, 0, ...] = glyph_patch0
        for i in range(1, patches.shape[0]):
            glyph_patches[i, 0,
                          ...] = glyph(patches[i, offset_index, ...],
                                       vectors_block_size=glyph_block_size,
                                       use_negative=glyph_use_negative)
        # correct patch centers
        glyph_patch_centers = UniformScale(glyph_block_size,
                                           2).apply(patch_centers)
        # visualize glyph patches
        renderer = view_patches(
            glyph_patches,
            glyph_patch_centers,
            patches_indices=patches_indices,
            offset_index=0,
            figure_id=renderer.figure_id,
            new_figure=False,
            background=background,
            render_patches=render_patches,
            channels=0,
            interpolation=interpolation,
            cmap_name=cmap_name,
            alpha=alpha,
            render_patches_bboxes=render_patches_bboxes,
            bboxes_line_colour=bboxes_line_colour,
            bboxes_line_style=bboxes_line_style,
            bboxes_line_width=bboxes_line_width,
            render_centers=render_centers,
            render_lines=render_lines,
            line_colour=line_colour,
            line_style=line_style,
            line_width=line_width,
            render_markers=render_markers,
            marker_style=marker_style,
            marker_size=marker_size,
            marker_face_colour=marker_face_colour,
            marker_edge_colour=marker_edge_colour,
            marker_edge_width=marker_edge_width,
            render_numbering=render_numbering,
            numbers_horizontal_align=numbers_horizontal_align,
            numbers_vertical_align=numbers_vertical_align,
            numbers_font_name=numbers_font_name,
            numbers_font_size=numbers_font_size,
            numbers_font_style=numbers_font_style,
            numbers_font_weight=numbers_font_weight,
            numbers_font_colour=numbers_font_colour,
            render_axes=render_axes,
            axes_font_name=axes_font_name,
            axes_font_size=axes_font_size,
            axes_font_style=axes_font_style,
            axes_font_weight=axes_font_weight,
            axes_x_limits=axes_x_limits,
            axes_y_limits=axes_y_limits,
            axes_x_ticks=axes_x_ticks,
            axes_y_ticks=axes_y_ticks,
            figure_size=figure_size)
    elif sum_enabled and render_patches:
        # compute sum of each patch
        sum_patches = np.zeros(
            (patches.shape[0], 1, 1, patches.shape[3], patches.shape[4]))
        for i in patches_indices:
            sum_patches[i, 0, ...] = sum_channels(patches[i, offset_index,
                                                          ...],
                                                  channels=channels)
        # visualize sum patches
        renderer = view_patches(
            sum_patches,
            patch_centers,
            patches_indices=patches_indices,
            offset_index=0,
            figure_id=renderer.figure_id,
            new_figure=False,
            background=background,
            render_patches=render_patches,
            channels=0,
            interpolation=interpolation,
            cmap_name=cmap_name,
            alpha=alpha,
            render_patches_bboxes=render_patches_bboxes,
            bboxes_line_colour=bboxes_line_colour,
            bboxes_line_style=bboxes_line_style,
            bboxes_line_width=bboxes_line_width,
            render_centers=render_centers,
            render_lines=render_lines,
            line_colour=line_colour,
            line_style=line_style,
            line_width=line_width,
            render_markers=render_markers,
            marker_style=marker_style,
            marker_size=marker_size,
            marker_face_colour=marker_face_colour,
            marker_edge_colour=marker_edge_colour,
            marker_edge_width=marker_edge_width,
            render_numbering=render_numbering,
            numbers_horizontal_align=numbers_horizontal_align,
            numbers_vertical_align=numbers_vertical_align,
            numbers_font_name=numbers_font_name,
            numbers_font_size=numbers_font_size,
            numbers_font_style=numbers_font_style,
            numbers_font_weight=numbers_font_weight,
            numbers_font_colour=numbers_font_colour,
            render_axes=render_axes,
            axes_font_name=axes_font_name,
            axes_font_size=axes_font_size,
            axes_font_style=axes_font_style,
            axes_font_weight=axes_font_weight,
            axes_x_limits=axes_x_limits,
            axes_y_limits=axes_y_limits,
            axes_x_ticks=axes_x_ticks,
            axes_y_ticks=axes_y_ticks,
            figure_size=figure_size)
    else:
        renderer = view_patches(
            patches,
            patch_centers,
            patches_indices=patches_indices,
            offset_index=offset_index,
            figure_id=renderer.figure_id,
            new_figure=False,
            background=background,
            render_patches=render_patches,
            channels=channels,
            interpolation=interpolation,
            cmap_name=cmap_name,
            alpha=alpha,
            render_patches_bboxes=render_patches_bboxes,
            bboxes_line_colour=bboxes_line_colour,
            bboxes_line_style=bboxes_line_style,
            bboxes_line_width=bboxes_line_width,
            render_centers=render_centers,
            render_lines=render_lines,
            line_colour=line_colour,
            line_style=line_style,
            line_width=line_width,
            render_markers=render_markers,
            marker_style=marker_style,
            marker_size=marker_size,
            marker_face_colour=marker_face_colour,
            marker_edge_colour=marker_edge_colour,
            marker_edge_width=marker_edge_width,
            render_numbering=render_numbering,
            numbers_horizontal_align=numbers_horizontal_align,
            numbers_vertical_align=numbers_vertical_align,
            numbers_font_name=numbers_font_name,
            numbers_font_size=numbers_font_size,
            numbers_font_style=numbers_font_style,
            numbers_font_weight=numbers_font_weight,
            numbers_font_colour=numbers_font_colour,
            render_axes=render_axes,
            axes_font_name=axes_font_name,
            axes_font_size=axes_font_size,
            axes_font_style=axes_font_style,
            axes_font_weight=axes_font_weight,
            axes_x_limits=axes_x_limits,
            axes_y_limits=axes_y_limits,
            axes_x_ticks=axes_x_ticks,
            axes_y_ticks=axes_y_ticks,
            figure_size=figure_size)

    # show plot
    plt.show()

    return renderer