Açıkladığınız şey Segmentasyon Sorunu . Bunun aslında çözülmemiş bir sorun olduğunu söylediğim için üzgünüm. Ama bunun için tavsiye edebileceğim bir yöntem Graph-Cut tabanlı algoritma. Grafik Kes, görüntüyü yerel olarak bağlı düğümlerin grafiği olarak temsil eder. Grafiğin bağlı bileşenlerini, iki alt bileşen arasındaki sınırın Max-flow-min-cut teoremi ve Ford Fulkerson algoritması kullanılarak minimum uzunlukta olacağı şekilde yinelemeli olarak alt bölümlere ayırır .
Esasen, tüm su kiremitlerini bir grafiğe bağlarsınız. Bitişik su kiremitleri arasındaki farklara karşılık gelen grafikteki kenarlara ağırlık atayın. Ben sizin durumunuzda, tüm ağırlıklar 1 olabilir düşünüyorum. İstenilen bir sonuç elde etmek için farklı ağırlık düzenleri ile oynamak zorunda kalacak. Örneğin, kıyılara bitişiklik içeren bir ağırlık eklemeniz gerekebilir.
Ardından, grafiğin tüm bağlı bileşenlerini bulun. Bunlar bariz denizler / göller vb.
Son olarak, her bağlı bileşen için, iki yeni alt bileşeni birbirine bağlayan kenarlar minimum ağırlığa sahip olacak şekilde bileşeni özyineli olarak alt bölümlere ayırın . Tüm alt bileşenler minimum boyuta (yani bir denizin maksimum boyutu gibi) ulaşıncaya kadar veya iki bileşeni kesen kenarlar çok yüksek bir ağırlığa sahip oluncaya kadar tekrar tekrar alt gruplara ayırmaya devam edin. Son olarak, kalan tüm bağlı bileşenleri etiketleyin.
Bunun pratikte yapacağı şey, denizleri kanallardan birbirinden kesmek, ancak büyük okyanuslara yayılmamaktır.
İşte sözde kod:
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);
DÜZENLEME : Bu arada, tüm kenar ağırlıkları 1 ise, minimum deniz boyutu 40'a, maksimum kesim boyutu 1'e ayarlanmış örnekle algoritmanın yapacağı şey:
Parametrelerle oynayarak farklı sonuçlar elde edebilirsiniz. Örneğin en fazla 3 kesme boyutu, ana denizlerden oyulmuş çok sayıda körfezle sonuçlanacak ve 1 numaralı deniz, kuzey ve güneyde alt bölümlere ayrılacaktır. Minimum 20 deniz boyutu, merkezi denizin de yarıya bölünmesine neden olacaktır.