Lo que estás describiendo es el problema de segmentación . Lamento decir que en realidad es un problema sin resolver. Pero un método que recomendaría para esto es un algoritmo basado en Graph-Cut . Graph-Cut representa la imagen como un gráfico de nodos conectados localmente. Subdivide los componentes conectados del gráfico de forma recursiva de modo que el borde entre los dos subcomponentes tenga una longitud mínima utilizando el teorema de Max-flow-min-cut y el algoritmo de Ford Fulkerson .
Básicamente, conecta todas las baldosas de agua en un gráfico. Asigne pesos a los bordes en el gráfico que corresponden a las diferencias entre las baldosas de agua adyacentes. Creo que en su caso, todos los pesos podrían ser 1. Tendrá que jugar con diferentes esquemas de ponderación para obtener un resultado deseable. Es posible que tenga que agregar algo de peso que incluya adyacencia a las costas, por ejemplo.
Luego, encuentre todos los componentes conectados del gráfico. Estos son obvios mares / lagos, etc.
Finalmente, para cada componente conectado, subdividir recursivamente el componente de manera que los bordes que conectan los dos nuevos subcomponentes tengan un peso mínimo . Siga subdividiendo recursivamente hasta que todos los subcomponentes alcancen un tamaño mínimo (es decir, como el tamaño máximo de un mar), o si los bordes que cortan los dos componentes tienen un peso demasiado alto. Finalmente, etiquete todos los componentes conectados que quedan.
Lo que esto hará en la práctica es separar los mares entre sí en los canales, pero no a través de grandes extensiones de océanos.
Aquí está en pseudocódigo:
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);
EDITAR : Por cierto, esto es lo que haría el algoritmo con su ejemplo con un tamaño mínimo del mar establecido en alrededor de 40, con un tamaño de corte máximo de 1, si todos los pesos de borde son 1:
Al jugar con los parámetros, puede obtener resultados diferentes. Un tamaño de corte máximo de 3, por ejemplo, daría como resultado que muchas más bahías se separen de los mares principales, y el mar # 1 se subdividiría en la mitad norte y sur. Un tamaño mínimo del mar de 20 daría como resultado que el mar central también se dividiera por la mitad.