Ce que vous décrivez est le problème de segmentation . Je suis désolé de dire que c'est en fait un problème non résolu. Mais une méthode que je recommanderais pour cela est un algorithme basé sur Graph-Cut . Graph-Cut représente l'image sous forme de graphique de nœuds connectés localement. Il subdivise récursivement les composants connectés du graphique de telle sorte que la frontière entre les deux sous-composants est de longueur minimale en utilisant le théorème Max-flow-min-cut et le Ford Fulkerson algorithme de .
Essentiellement, vous connectez toutes les tuiles d'eau dans un graphique. Attribuez des poids aux bords du graphique qui correspondent aux différences entre les tuiles d'eau adjacentes. Je pense que dans votre cas, tous les poids pourraient être 1. Vous devrez jouer avec différents schémas de pondération pour obtenir un résultat souhaitable. Vous devrez peut-être ajouter un poids qui inclut la contiguïté aux côtes, par exemple.
Ensuite, trouvez tous les composants connectés du graphique. Ce sont des mers / lacs évidents et ainsi de suite.
Enfin, pour chaque composant connecté, subdivisez récursivement le composant de sorte que les bords reliant les deux nouveaux sous-composants aient un poids minimal . Continuez à subdiviser récursivement jusqu'à ce que tous les sous-composants atteignent une taille minimale (c'est-à-dire comme la taille maximale d'une mer), ou si les bords coupant les deux composants ont un poids trop élevé. Enfin, étiquetez tous les composants connectés qui restent.
Dans la pratique, cela se traduira par une séparation des mers les uns des autres dans les chenaux, mais pas sur de grandes étendues d'océans.
Le voici en pseudocode:
function SegmentGraphCut(Map worldMap, int minimumSeaSize, int maximumCutSize)
Graph graph = new Graph();
// First, build the graph from the world map.
foreach Cell cell in worldMap:
// The graph only contains water nodes
if not cell.IsWater():
continue;
graph.AddNode(cell);
// Connect every water node to its neighbors
foreach Cell neighbor in cell.neighbors:
if not neighbor.IsWater():
continue;
else:
// The weight of an edge between water nodes should be related
// to how "similar" the waters are. What that means is up to you.
// The point is to avoid dividing bodies of water that are "similar"
graph.AddEdge(cell, neighbor, ComputeWeight(cell, neighbor));
// Now, subdivide all of the connected components recursively:
List<Graph> components = graph.GetConnectedComponents();
// The seas will be added to this list
List<Graph> seas = new List<Graph>();
foreach Graph component in components:
GraphCutRecursive(component, minimumSeaSize, maximumCutSize, seas);
// Recursively subdivides a component using graph cut until all subcomponents are smaller
// than a minimum size, or all cuts are greater than a maximum cut size
function GraphCutRecursive(Graph component, int minimumSeaSize, int maximumCutSize, List<Graph> seas):
// If the component is too small, we're done. This corresponds to a small lake,
// or a small sea or bay
if(component.size() <= minimumSeaSize):
seas.Add(component);
return;
// Divide the component into two subgraphs with a minimum border cut between them
// probably using the Ford-Fulkerson algorithm
[Graph subpartA, Graph subpartB, List<Edge> cut] = GetMinimumCut(component);
// If the cut is too large, we're done. This corresponds to a huge, bulky ocean
// that can't be further subdivided
if (GetTotalWeight(cut) > maximumCutSize):
seas.Add(component);
return;
else:
// Subdivide each of the new subcomponents
GraphCutRecursive(subpartA, minimumSeaSize, maximumCutSize);
GraphCutRecursive(subpartB, minimumSeaSize, maximumCutSize);
EDIT : Soit dit en passant, voici ce que l'algorithme ferait avec votre exemple avec une taille de mer minimale définie à environ 40, avec une taille de coupe maximale de 1, si tous les poids des bords sont 1:
En jouant avec les paramètres, vous pouvez obtenir des résultats différents. Une taille de coupe maximale de 3, par exemple, entraînerait la création de nombreuses baies dans les mers principales, et la mer n ° 1 se diviserait en deux moitiés nord et sud. Une taille de mer minimale de 20 entraînerait également la division de la mer centrale en deux.