Was Sie beschreiben, ist das Segmentierungsproblem . Es tut mir leid zu sagen, dass es sich tatsächlich um ein ungelöstes Problem handelt. Eine Methode, die ich dafür empfehlen würde, ist ein Graph-Cut- basierter Algorithmus. Graph-Cut repräsentiert das Bild als Graph lokal verbundener Knoten. Es unterteilt zusammenhängende Komponenten des Graphen rekursiv so, dass die Grenze zwischen den beiden Unterkomponenten unter Verwendung des Max-Flow-Min-Cut-Theorems und des Ford-Fulkerson- Algorithmus von minimaler Länge ist .
Im Wesentlichen verbinden Sie alle Wasserplättchen zu einem Diagramm. Weisen Sie den Kanten in der Grafik Gewichte zu, die den Unterschieden zwischen den benachbarten Wasserplättchen entsprechen. Ich denke, in Ihrem Fall könnten alle Gewichte 1 sein. Sie müssen mit verschiedenen Gewichtungsschemata spielen, um ein wünschenswertes Ergebnis zu erzielen. Möglicherweise müssen Sie ein Gewicht hinzufügen, das beispielsweise die Nähe zu Küsten umfasst.
Suchen Sie dann alle verbundenen Komponenten des Diagramms. Dies sind offensichtliche Meere / Seen und so weiter.
Teilen Sie die Komponente schließlich für jede verbundene Komponente rekursiv so auf, dass die Kanten, die die beiden neuen Unterkomponenten verbinden, ein Mindestgewicht haben . Untergliedern Sie weiter rekursiv, bis alle Unterkomponenten eine minimale Größe erreicht haben (dh wie die maximale Größe eines Meeres), oder wenn die Kanten, die die beiden Komponenten schneiden, ein zu hohes Gewicht haben. Beschriften Sie abschließend alle angeschlossenen Komponenten, die noch vorhanden sind.
In der Praxis wird dies dazu führen, dass die Meere an Kanälen voneinander getrennt werden, jedoch nicht über große Ozeane hinweg.
Hier ist es im 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 : Übrigens, hier ist, was der Algorithmus mit Ihrem Beispiel mit einer minimalen Meeresgröße von ungefähr 40 und einer maximalen Schnittgröße von 1 machen würde, wenn alle Kantengewichte 1 sind:
Indem Sie mit den Parametern spielen, können Sie unterschiedliche Ergebnisse erzielen. Eine maximale Schnittgröße von 3 würde zum Beispiel dazu führen, dass viel mehr Buchten aus den Hauptmeeren herausgearbeitet werden, und das Meer Nr. 1 würde in die Hälften Nord und Süd unterteilt. Eine minimale Meeresgröße von 20 würde dazu führen, dass das Zentralmeer ebenfalls in zwei Hälften geteilt wird.