Document

publicité
Utilisation des Graphes
dans Morph-M
Jean Stawiaski
Centre de Morphologie Mathématique
2 décembre 2008
1
Sommaire
Introduction Morph-M (CommonGraph32) et (BoostGraph)
1) Passage Graphe-Image et Image-Graphe
1.1 Graphe d’une image
1.2 Graphe d’une partition
2) Utilisation des Graphes (CommonGraph32) en Python
2.1 Fonctions de base
2.2 Exemples, opérations de base de morphologie mathématique
3) Utilisation des Graphes en C++
3.1 Création d’un graphe en C++
3.2 Fonction de base
3.3 Algorithmes
3.4 Exemples
4) Pour aller un peu plus loin
Conclusion
2
Introduction : Vocabulaire
Un graphe G est une paire G = (V,E) où V est un ensemble finis appelé nœuds du graphe et E
est une ensemble finis appelé les arêtes du graphe.
i ei,j j
Il est possible de différencier les arêtes ei,j et ej,i, on parle alors de graphes orientés.
Il est possible d’associer à un graphe G, un ensemble de valeurs associés aux nœuds ou un
ensemble associé aux arêtes. On parle de graphes aux nœuds valués ou bien de graphes aux arêtes
valuées.
3
Introduction : BoostGraph
Les graphes de la librairie Boost, dénommés BoostGraph, est une structure générique pouvant
représenté à peu près n’importe quel type de graphes.
La structure BoostGraph représente des graphes orientés ou non, pouvant être valués aux
nœuds et aux arrêtes.
La valuation des arrêtes et des nœuds sont aussi représentés par des structures abstraites.
BoostGraph Library met à disposition un grand nombre d’algorithmes (Dijkstra, Kruskal, Prim,
Ford-Fulkerson, etc.)
4
Introduction : CommonGraph32
Les graphes sous Morph-M sont utilisés à travers la structure appelé CommonGraph32.
La structure CommonGraph32 représente un graphe non-orienté, valué aux nœuds et aux
arrêtes.
La valuation des arrêtes et des nœuds sont des entiers codés sur 32 bits
La structure CommonGraph32 est définie à partir de la librairie Boost.
La structure CommonGraph32 est accessible en C++ et en Python.
La structure CommonGraph32 est utilisée dans Morph-M pour représenter des images et des
partitions.
5
1) Passage Graphe-Image et Image-Graphe
6
1) Passage Graphe-Image et Image-Graphe
1.1 Graphe d’une image
Passage image
graphe. Représentation d’une image par un graphe (nœuds = pixels, arrêtes =
relations de voisinage).
MorphoGraph.GetPixelGraph(im,nl,G)
nl = CrossSE
Passage graphe
nl = SquareSE
image. Projette les valeurs des nœuds sur les pixels de l’image.
MorphoGraph.ProjectGraphOnPixel(G,imOut)
Projection d’une image sur le graphe. Remplace la valeurs des nœuds du graphe par les valeurs
des pixels.
MorphoGraph.ProjectMarkersOnPixelGraph(ImIn, Gout)
7
1) Passage Graphe-Image et Image-Graphe
1.2 Graphe d’une partition
Passage image
graphe. Représentation d’une mosaïque par un graphe (nœuds = régions,
arrêtes = relations de voisinage).
G = Morphee.NeighborhoodGraphFromMosaic(imMosaic, nl)
G = Morphee.NeighborhoodGraphFromMosaicWithPass(imMosaic, imGrad, nl)
Passage graphe
image. Projette les valeurs des nœuds sur les régions de la mosaïque.
Morphee.ProjectGraphOnSegmentation(G, imMosaic,imOut)
Projection d’une image sur le graphe. Remplace la valeurs des nœuds du graphe par les valeurs
des régions.
Morphee.ProjectMarkersOnGraph(Immarkers,imMosaic,Gout)
8
2) Utilisation des Graphes
(CommonGraph32) en Python
9
2) Utilisation des (CommonGraph32) en Python
2.1 Fonctions de base
La plupart des fonctions associées aux graphes sont accessibles à partir de Morph-M et
d’un module spécifique Morpho-Graph :
- Morph-M contient les outils associés à la segmentation (hiérarchie, mst, graphes de
régions, etc.),
- Morpho-Graph contient des fonctions de base de morphologie mathématique sur les
graphes (Erosion, Dilatation, etc.) , ainsi que des fonctions de base pour graphes
(labellisation, chemins les plus courts, coupe minimale, flots, etc.).
10
2) Utilisation des (CommonGraph32) en Python
2.1 Fonctions de base
Création d’un graphe : G=morphee.CommonGraph32(numVertices)
Les nœuds sont accéder par leurs descripteurs v, offset pour les graphes de pixels, labels de la
régions -1 pour les graphes de régions)
Récupérer le nombre de nœuds G.numVertices()
Récupérer la valeur d’un nœud G.getVertexData(v)
Imposer la valeur d’un nœud G.setVertexData(v,val)
Obtenir les voisins d’un nœud G.getChildren(v1)
Récupérer le nombre d’arrêtes G.numEdges()
Récupérer la valeur d’une arrête G.getEdgeWeight(v1,v2)
Imposer la valeur d’une arrête G.setEdgeWeight(v1,v2,val)
Récupérer les arrêtes d’un graphe et leurs valeurs edgeList = G.getEdgesListAndWeights()
11
2) Utilisation des (CommonGraph32) en Python
2.2 Exemples
for v1 in range( G.numVertices() ):
G.setVertexData( v1, 0 )
edgeList = G.getEdgesListAndWeights()
for v1,v2,w in edgeList:
G.setEdgeWeight(v1,v2,0)
for v1 in range( G.numVertices() ):
for v2 in G.getChildren(v1):
newVal = max (G.getVertexData(v2), newVal )
G2.setVertexData( v1, newVal )
12
2) Utilisation des (CommonGraph32) en Python
2.2 Exemples
edgeList = G.getEdgesListAndWeights()
for s,t,w in edgeList:
newW = max ( G.getVertexData(s) , G.getVertexData(t) )
G.setEdgeWeight(s,t,newW)
for v1 in range( G.numVertices() ):
for v2 in G.getChildren(v1):
newVal = max ( G.getEdgeWeight( v1, v2 ), newVal )
G.setVertexData( v1, newVal )
13
2) Utilisation des (CommonGraph32) en Python
2.2 Exemples : Opérations de base de morphologie mathématique
ErosionNodesToEdges(graphIn,graphOut)
DilationNodesToEdges(graphIn,graphOut)
ErosionEdgesToNodes(graphIn,graphOut)
DilationEdgesToNodes(graphIn,graphOut)
ErosionNodesToNodes(graphIn,graphOut)
DilationNodesToNodes(graphIn,graphOut)
DilationEdgesToEdges(graphIn,graphOut)
ErosionEdgesToEdges(graphIn,graphOut)
14
2) Utilisation des (CommonGraph32) en Python
2.2 Exemples
def GetGraphFromFlatZones( im, nl ):
imLab=morphee.getSameOf(im, morphee.dataCategory.dtScalar, morphee.scalarDataType.sdtUINT32)
morphee.ImLabelFlatZones( im, nl, imLab )
G = morphee.NeighborhoodGraphFromMosaic_WithAverageAndDifference(imLab,im, nl )
return G,imLab
def GetGraphFromWatershed( imIn, nl):
imGrad = morphee.getSame( imIn )
morphee.ImMorphoGradient(imIn,nl,imGrad)
imMinima32=morphee.getSameOf(imGrad, morphee.dataCategory.dtScalar, morphee.scalarDataType.sdtUINT32)
morphee.ImMinima(imGrad,nl,imMinima32)
imLabel32=morphee.getSame(imMinima32)
morphee.ImLabel(imMinima32,nl,imLabel32)
imWS32=morphee.getSame(imMinima32)
morphee.ImBasinsConstrainedNoWSLine_v2(imGrad,imLabel32,nl,imWS32)
G = morphee.NeighborhoodGraphFromMosaic_WithPass(imWS32,imGrad, nl )
return G, imWS32
15
2) Utilisation des (CommonGraph32) en Python
2.2 Exemples
def GetGraphFromHierarchicalSegmentation( im, nl, numRegions, wsType):
imGrad = morphee.getSame(im)
morphee.ImMorphoGradient( im, nl, imGrad )
imMinima32=morphee.getSameOf(imGrad, morphee.dataCategory.dtScalar, morphee.scalarDataType.sdtUINT32)
morphee.ImMinima(imGrad,nl,imMinima32)
imLabel32=morphee.getSame(imMinima32)
morphee.ImLabel(imMinima32,nl,imLabel32)
imWS32=morphee.getSame(imMinima32)
hierGraph=morphee.ImHierarchicalSegmentation32(imGrad,imLabel32,nl,wsType,imWS32)
Forest=morphee.ImDisplayHierarchyLevel32(imWS32,hierGraph,numRegions,imOut32)
return Forest, imOut32
16
3) Utilisation des Graphes en C++
17
3) Utilisation des Graphes en C++
3.1 Création d’un graphe en C++ avec Boost : Introduction
Un graphe est représenté par une liste d’adjacence :
Le type des entrées de la liste d’adjacence est spécifié par des paramètres de la classe graphe.
18
3) Utilisation des Graphes en C++
3.1 Création d’un graphe en C++ avec Boost
VertexList et OutEdgeList défini le type d’objet utilisé pour décrire le graphe (std::list, set,
vect). Ce choix a un impact sur la complexité des algorithmes.
Les propriétés du graphe comme les couleurs, les distances, les poids des arrêtes, sont
définis par l’utilisateur dans les propriétés VertexProperties, EdgeProperties,
GraphProperties.
Les propriétés du graphe sont définies en C++ par des std::maps.
19
3) Utilisation des Graphes en C++
3.1 Création d’un graphe en C++ avec Boost
Exemple : Graphe non orienté, valué aux arrêtes, et valué aux nœuds par un double.
typedef boost::adjacency_list < boost::vecS, boost::vecS, boost::undirectedS,
boost::property < boost::vertex_distance_t, double >,
boost::property < boost::edge_capacity_t, double > > Graph_d;
20
3) Utilisation des Graphes en C++
3.2 Fonction de base : Méthodes de CommonGraph32 et Boost
graph_traits<adjacency_list>::vertex_descriptor
graph_traits<adjacency_list>::edge_descriptor
graph_traits<adjacency_list>::vertex_iterator
graph_traits<adjacency_list>::edge_iterator
boost::tie(v_iter, v_end)= boost::vertices(G)
boost::tie(e_iter, e_end)=boost::edges(G)
graph_traits<adjacency_list>::out_edge_iterator
boost::tie(e_iter, e_end)=boost::out_edges(v,G)
property_map<adjacency_list, PropertyTag>::type get(PropertyTag, adjacency_list& g)
21
3) Utilisation des Graphes en C++
3.2 Fonction de base : Méthodes de CommonGraph32 et Boost
G.edgeFromVertices(v1,v2,&e)
v1 = G.edgeSource(e)
v2 = G.edgeTarget(e)
G.vertexData(v, &vdata)
G.edgeWeight(e,&edgeweight)
G.setVertexData(v,val)
G.setEdgeWeight(e, val )
G.removeEdge(v1,v2)
G.addEdge(v1,v2)
G.addVertex()
G.removeVertex(v1)
( e, in ) = boost::edge(v1,v2,g)
boost::source(e,g)
Boost::target(e,g)
property_map<Graph, edge_capacity_t>::type
weight = boost::get(edge_capacity, g);
boost::remove_edge( param , g)
boost::add_edge(v1,v2,g)
boost::add_vertex(g)
boost::remove_vertex(v,g)
g = G.getBoostGraph()
22
3) Utilisation des Graphes en C++
3.3 Exemples
for ( boost::tie(ed_it, ed_end) = boost::edges(GIn.getBoostGraph()) ;ed_it != ed_end ; ++ed_it , ++edout) {
GIn.edgeWeight(*ed_it,&tmp);
if( tmp > seuil){
Gout.removeEdge( typename Graph::VertexDescriptor(GIn.edgeSource(*ed_it)),
typename Graph::VertexDescriptor(GIn.edgeTarget(*ed_it)) );
}
}
morphee::Morpho_Graph::ErosionEdgesToEdges(GIn, GEro);
morphee::Morpho_Graph::DilationEdgesToEdges(GIn,GDil);
for (boost::tie(ed_it, ed_end)=boost::edges(GIn.getBoostGraph()); ed_it != ed_end ; ++ed_it ) {
GIn.edgeWeight(*ed_it,&tmp);
GEro.edgeWeight(*edero_it,&tmp1);
GDil.edgeWeight(*eddil_it,&tmp2);
if(std::abs( (double) tmp - (double) tmp1) <= std::abs( (double) tmp2 - (double) tmp))
Gout.setEdgeWeight( *edout, tmp1 );
else
Gout.setEdgeWeight( *edout, tmp2 );
}
23
3) Utilisation des Graphes en C++
3.4 Algorithmes (liste non exhaustive)
Breadth First Search
Depth First Search
Uniform Cost Search
Dijkstra's Shortest Paths
Bellman-Ford Shortest Paths
Johnson's All-Pairs Shortest Paths
Kruskal's Minimum Spanning Tree
Prim's Minimum Spanning Tree
Edmund Karp Maximal flow
Tarjan Push relabel max flow
Kolmogorov max flow
Edmund max cardinality matching
Connected Components
Strongly Connected Components
Sequential Vertex Coloring
24
3) Utilisation des Graphes en C++
3.4 Algorithmes
Composantes connexes
std::vector<int> component(boost::num_vertices(GIn.getBoostGraph()));
int num = connected_components(GIn.getBoostGraph(), &component[0]);
for (boost::tie(u_iter, u_end)=boost::vertices(GIn.getBoostGraph()) ; u_iter != u_end; ++u_iter){
Gout.setVertexData(*u_iter,component[*u_iter]); }
Arbre de recouvrement 1
std::vector< typename BoostGraph::EdgeDescriptor > v_spanning_tree;
boost::kruskal_minimum_spanning_tree( (graphIn).getBoostGraph(), std::back_inserter(v_spanning_tree) ) ;
Arbre de recouvrement 2
std::vector< typename BoostGraph::VertexDescriptor > p(boost::num_vertices((graphIn).getBoostGraph());
boost::prim_minimum_spanning_tree( (graphIn).getBoostGraph(), &p[0] ) ;
25
3) Utilisation des Graphes en C++
3.4 Algorithmes
Chemins les plus courts
boost::property_map< typename BoostGraph, boost::edge_capacity_t>::type weightmap =
boost::get(boost::edge_capacity, g );
std::vector < typename BoostGraph::vertex_descriptor > p(boost::num_vertices(g));
boost::property_map < typename BoostGraph, boost::vertex_distance_t>::type distancemap =
boost::get(boost::vertex_distance, g);
boost::property_map< typename BoostGraph, boost::vertex_index_t>::type indexmap2 = boost::get(boost::vertex_index, g);
dijkstra_shortest_paths(g, vRoot, &p[0], distancemap, weightmap, indexmap2, std::less<double>(),
boost::closed_plus<double>(), (std::numeric_limits<double>::max)(), 0,
boost::default_dijkstra_visitor());
L’Algorithme de Dijkstra permet de calculer les chemins les plus courts dans l’algèbre de
chemins ( type distancemap, comparaison, combinaison, 0, infini)
26
3) Utilisation des Graphes en C++
3.4 Algorithmes
Flot maximal et coupe minimale
boost::property_map<Graph_d, boost::edge_capacity_t>::type capacity = boost::get(boost::edge_capacity, g);
boost::property_map<Graph_d, boost::edge_reverse_t>::type rev = get(boost::edge_reverse, g);
boost::property_map<Graph_d, boost::edge_residual_capacity_t>::type residual_capacity = get(boost::edge_residual_capacity, g)
boost::property_map<Graph_d, boost::vertex_index_t>::type indexmap = boost::get(boost::vertex_index, g);
std::vector<boost::default_color_type> color(boost::num_vertices(g));
flow = kolmogorov_max_flow(g, capacity, residual_capacity, rev, &color[0], indexmap, vSource, vSink);
Les algorithmes de flots et coupes ne peuvent pas être directement utilisés sur des
CommonGraph32….
27
4) Pour aller un peu plus loin…
28
4) Pour aller un peu plus loin…
1) Tirer Avantage de la généricité des algorithmes :
Quelle est la différence entre :
dijkstra_shortest_paths(g, vRoot, &p[0], distancemap, weightmap, indexmap2, std::less<double>(),
boost::closed_plus<double>(),
(std::numeric_limits<double>::max)(), 0, boost::default_dijkstra_visitor());
dijkstra_shortest_paths(g, vRoot, &p[0], distancemap, weightmap, indexmap2, std::less<double>(),
std::max<double>(),
(std::numeric_limits<double>::max)(), 0, boost::default_dijkstra_visitor());
Le seul algorithme de Dijstra permet de calculer les arbres de recouvrement min et max, les
chemins les plus courts, les chemins les plus probables, etc.
29
4) Pour aller un peu plus loin…
2) Tirer Avantage de la généricité des structures :
typedef std::vector<double> vdouble;
typedef boost::adjacency_list < boost::vecS, boost::vecS, boost::undirectedS,
boost::property < boost::vertex_distance_t, vdouble >, boost::property < boost::edge_capacity_t, vdouble > > Graph_v;
Graph_v est un type de graphe dont les arrêtes sont valués par des vecteurs, et les nœuds
valués par des vecteurs. De plus, la taille de ces vecteurs n’est pas défini, et peut donc être
variable selon les arrêtes ou selon les nœuds.
Graph_v peut être utilisé pour représenter des images multi-valués ou le nombre de canaux
varient selon les pixels, ou les disimilarités entre pixels sont représentés par des vecteurs de
taille variable.
30
4) Pour aller un peu plus loin…
2) Tirer Avantage de la généricité des structures :
typedef std::vector<double> vdouble;
typedef boost::adjacency_list < boost::vecS, boost::vecS, boost::undirectedS,
boost::property < boost::vertex_distance_t, vdouble >, boost::property < boost::edge_capacity_t, vdouble > > Graph_v;
dijkstra_shortest_paths(g, vRoot, &p[0], distancemap, weightmap, indexmap2,
boost::detail::lexico_compare< vdouble > () ,
boost::detail::lexico_addition< vdouble > (),
infinite,
zero,
boost::default_dijkstra_visitor());
Comparaison lexico de vecteurs
Concaténation de vecteurs
Transformée en distance lexicographique, la distance est donnée par un vecteur de taille
variable (la valeur des arrêtes en ordre décroissant le long d’un chemin)
31
4) Pour aller un peu plus loin…
2) Tirer Avantage de la généricité des structures :
Dijkstra a été utilisé pour :
- distance classique
- mst
- distance multi-critères lexicographique
- distance lexicographique sur image à niveaux de gris
- mst sur image couleur (max de deux vecteurs ordonnés)
- distance lexicographique sur image couleur
- chemins les plus probables
- etc.
32
Conclusion
33
Conclusion
Le développement actuel du module graphe de Morph-M donne accès à une large gamme
d’algorithmes utilisable en C++ et en Python.
La librairie Boost évolué régulièrement, nous utilisons actuellement seulement une petite
partie des algorithmes codés dans Boost\Graph.
Le module Morpho-Graph est en cours de migration (développement de tests unitaires, etc.)
La structure de graphe est actuellement la structure la plus générique utilisable pour le
traitement d’images (graphes valués par des vecteurs, opérations de voisinage, algorithmes
d’optimisation combinatoire, etc.)
Développement actuel : Boite à outils pour les arbres (suite du module Morphee\Commontree)
LPE stochastique
Filtrage topologique des graphes
Filtrage par critères
Filtre Morphologique
etc.
34
Merci pour votre attention
Questions ?
35
Téléchargement