Source code for menpo.shape.graph_predefined

from menpo.landmark import LandmarkGroup
from . import (PointCloud, UndirectedGraph, DirectedGraph, Tree, TriMesh,
               PointUndirectedGraph, PointDirectedGraph, PointTree)


def _get_points_and_number_of_vertices(shape):
    if isinstance(shape, LandmarkGroup):
        return shape.lms.points, shape.n_landmarks
    elif isinstance(shape, PointCloud):
        return shape.points, shape.n_points
    else:
        raise ValueError("shape must be either a LandmarkGroup or a "
                         "PointCloud instance.")


def _get_star_graph_edges(vertices_list, root_vertex):
    edges = []
    for v in vertices_list:
        if v != root_vertex:
            edges.append([root_vertex, v])
    return edges


def _get_complete_graph_edges(vertices_list):
    n_vertices = len(vertices_list)
    edges = []
    for i in range(n_vertices-1):
        k = i + 1
        for j in range(k, n_vertices, 1):
            v1 = vertices_list[i]
            v2 = vertices_list[j]
            edges.append([v1, v2])
    return edges


def _get_chain_graph_edges(vertices_list, closed):
    n_vertices = len(vertices_list)
    edges = []
    for i in range(n_vertices-1):
        k = i + 1
        v1 = vertices_list[i]
        v2 = vertices_list[k]
        edges.append([v1, v2])
    if closed:
        v1 = vertices_list[-1]
        v2 = vertices_list[0]
        edges.append([v1, v2])
    return edges


[docs]def empty_graph(shape, return_pointgraph=True): r""" Returns an empty graph given the landmarks configuration of a shape instance. Parameters ---------- shape : :map:`PointCloud` or :map:`LandmarkGroup` or subclass The shape instance that defines the landmarks configuration based on which the graph will be created. return_pointgraph : `bool`, optional If ``True``, then a :map:`PointUndirectedGraph` instance will be returned. If ``False``, then an :map:`UndirectedGraph` instance will be returned. Returns ------- graph : :map:`UndirectedGraph` or :map:`PointUndirectedGraph` The generated graph. """ # get points and number of vertices points, n_vertices = _get_points_and_number_of_vertices(shape) # create empty edges edges = None # return graph if return_pointgraph: return PointUndirectedGraph.init_from_edges(points, edges, n_vertices, skip_checks=True) else: return UndirectedGraph.init_from_edges(edges, n_vertices, skip_checks=True)
[docs]def star_graph(shape, root_vertex, graph_cls=PointTree): r""" Returns a star graph given the landmarks configuration of a shape instance. Parameters ---------- shape : :map:`PointCloud` or :map:`LandmarkGroup` or subclass The shape instance that defines the landmarks configuration based on which the graph will be created. root_vertex : `int` The root of the star tree. graph_cls : `Graph` or `PointGraph` subclass The output graph type. Possible options are :: {:map:`UndirectedGraph`, :map:`DirectedGraph`, :map:`Tree`, :map:`PointUndirectedGraph`, :map:`PointDirectedGraph`, :map:`PointTree`} Returns ------- graph : `Graph` or `PointGraph` subclass The generated graph. Raises ------ ValueError graph_cls must be UndirectedGraph, DirectedGraph, Tree, PointUndirectedGraph, PointDirectedGraph or PointTree. """ # get points and number of vertices points, n_vertices = _get_points_and_number_of_vertices(shape) # create star graph edges edges = _get_star_graph_edges(range(n_vertices), root_vertex) # return graph if graph_cls == Tree: return graph_cls.init_from_edges(edges=edges, n_vertices=n_vertices, root_vertex=root_vertex, skip_checks=True) elif graph_cls == PointTree: return graph_cls.init_from_edges(points=points, edges=edges, root_vertex=root_vertex, skip_checks=True) elif graph_cls == UndirectedGraph or graph_cls == DirectedGraph: return graph_cls.init_from_edges(edges=edges, n_vertices=n_vertices, skip_checks=True) elif graph_cls == PointUndirectedGraph or graph_cls == PointDirectedGraph: return graph_cls.init_from_edges(points=points, edges=edges, skip_checks=True) else: raise ValueError("graph_cls must be UndirectedGraph, DirectedGraph, " "Tree, PointUndirectedGraph, PointDirectedGraph or " "PointTree.")
[docs]def complete_graph(shape, graph_cls=PointUndirectedGraph): r""" Returns a complete graph given the landmarks configuration of a shape instance. Parameters ---------- shape : :map:`PointCloud` or :map:`LandmarkGroup` or subclass The shape instance that defines the landmarks configuration based on which the graph will be created. graph_cls : `Graph` or `PointGraph` subclass The output graph type. Possible options are :: {:map:`UndirectedGraph`, :map:`DirectedGraph`, :map:`PointUndirectedGraph`, :map:`PointDirectedGraph`} Returns ------- graph : `Graph` or `PointGraph` subclass The generated graph. Raises ------ ValueError graph_cls must be UndirectedGraph, DirectedGraph, PointUndirectedGraph or PointDirectedGraph. """ # get points and number of vertices points, n_vertices = _get_points_and_number_of_vertices(shape) # create complete graph edges edges = _get_complete_graph_edges(range(n_vertices)) # return graph if graph_cls == UndirectedGraph or graph_cls == DirectedGraph: return graph_cls.init_from_edges(edges=edges, n_vertices=n_vertices, skip_checks=True) elif graph_cls == PointUndirectedGraph or graph_cls == PointDirectedGraph: return graph_cls.init_from_edges(points=points, edges=edges, skip_checks=True) else: raise ValueError("graph_cls must be UndirectedGraph, DirectedGraph, " "PointUndirectedGraph or PointDirectedGraph.")
[docs]def chain_graph(shape, graph_cls=PointDirectedGraph, closed=False): r""" Returns a chain graph given the landmarks configuration of a shape instance. Parameters ---------- shape : :map:`PointCloud` or :map:`LandmarkGroup` or subclass The shape instance that defines the landmarks configuration based on which the graph will be created. graph_cls : `Graph` or `PointGraph` subclass The output graph type. Possible options are :: {:map:`UndirectedGraph`, :map:`DirectedGraph`, :map:`Tree`, :map:`PointUndirectedGraph`, :map:`PointDirectedGraph`, :map:`PointTree`} closed : `bool`, optional If ``True``, then the chain will be closed (i.e. edge between the first and last vertices). Returns ------- graph : `Graph` or `PointGraph` subclass The generated graph. Raises ------ ValueError A closed chain graph cannot be a Tree or PointTree instance. ValueError graph_cls must be UndirectedGraph, DirectedGraph, Tree, PointUndirectedGraph, PointDirectedGraph or PointTree. """ # get points and number of vertices points, n_vertices = _get_points_and_number_of_vertices(shape) # create chain graph edges edges = _get_chain_graph_edges(range(n_vertices), closed=closed) # return graph if graph_cls == Tree: if closed: raise ValueError("A closed chain graph cannot be a Tree " "instance.") else: return graph_cls.init_from_edges(edges=edges, n_vertices=n_vertices, root_vertex=0, skip_checks=True) elif graph_cls == PointTree: if closed: raise ValueError("A closed chain graph cannot be a PointTree " "instance.") else: return graph_cls.init_from_edges(points=points, edges=edges, root_vertex=0, skip_checks=True) elif graph_cls == UndirectedGraph or graph_cls == DirectedGraph: return graph_cls.init_from_edges(edges=edges, n_vertices=n_vertices, skip_checks=True) elif graph_cls == PointUndirectedGraph or graph_cls == PointDirectedGraph: return graph_cls.init_from_edges(points=points, edges=edges, skip_checks=True) else: raise ValueError("graph_cls must be UndirectedGraph, DirectedGraph, " "Tree, PointUndirectedGraph, PointDirectedGraph or " "PointTree.")
[docs]def delaunay_graph(shape, return_pointgraph=True): r""" Returns a graph with the edges being generated by Delaunay triangulation. Parameters ---------- shape : :map:`PointCloud` or :map:`LandmarkGroup` or subclass The shape instance that defines the landmarks configuration based on which the graph will be created. return_pointgraph : `bool`, optional If ``True``, then a :map:`PointUndirectedGraph` instance will be returned. If ``False``, then an :map:`UndirectedGraph` instance will be returned. Returns ------- graph : :map:`UndirectedGraph` or :map:`PointUndirectedGraph` The generated graph. """ # get TriMesh instance that estimates the Delaunay triangulation if isinstance(shape, LandmarkGroup): trimesh = TriMesh(shape.lms.points) n_vertices = shape.n_landmarks points = shape.lms.points elif isinstance(shape, PointCloud): trimesh = TriMesh(shape.points) n_vertices = shape.n_points points = shape.points else: raise ValueError("shape must be either a LandmarkGroup or a " "PointCloud instance.") # get edges edges = trimesh.edge_indices() # return graph if return_pointgraph: return PointUndirectedGraph.init_from_edges( points=points, edges=edges, skip_checks=True) else: return UndirectedGraph.init_from_edges( edges=edges, n_vertices=n_vertices, skip_checks=True)