Apa yang Anda gambarkan adalah Masalah Segmentasi . Saya minta maaf untuk mengatakan bahwa itu sebenarnya masalah yang belum terpecahkan. Tapi satu metode yang saya sarankan untuk ini adalah algoritma berbasis Graph-Cut . Graph-Cut mewakili gambar sebagai grafik dari node yang terhubung secara lokal. Ini membagi komponen yang terhubung dari grafik secara rekursif sehingga perbatasan antara dua sub-komponen memiliki panjang minimal menggunakan teorema Max-flow-min-cut dan algoritma Ford Fulkerson .
Intinya, Anda menghubungkan semua ubin air ke dalam grafik. Tetapkan bobot ke tepi pada grafik yang sesuai dengan perbedaan antara ubin air yang berdekatan. Saya pikir dalam kasus Anda, semua bobot bisa 1. Anda harus bermain dengan skema pembobotan yang berbeda untuk mendapatkan hasil yang diinginkan. Anda mungkin harus menambahkan beberapa bobot yang mencakup kedekatan dengan pantai, misalnya.
Kemudian, cari semua komponen grafik yang terhubung. Ini jelas laut / danau dan sebagainya.
Akhirnya, untuk setiap komponen yang terhubung, membagi komponen secara rekursif sedemikian rupa sehingga ujung-ujung yang menghubungkan dua sub-komponen baru memiliki bobot minimum . Teruslah membagi secara rekursif sampai semua sub-komponen mencapai ukuran minimum (yaitu seperti ukuran maksimum laut), atau jika tepian yang memotong kedua komponen memiliki bobot terlalu tinggi. Terakhir, beri label semua komponen yang terhubung yang tersisa.
Apa yang akan dilakukan dalam praktik ini adalah memotong laut dari satu sama lain di saluran, tetapi tidak melintasi samudera besar.
Ini dia dalam 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 : Omong-omong, inilah yang akan dilakukan algoritme dengan contoh Anda dengan ukuran laut minimum yang ditetapkan menjadi sekitar 40, dengan ukuran potong maksimum 1, jika semua bobot tepi adalah 1:
Dengan bermain dengan parameter, Anda bisa mendapatkan hasil yang berbeda. Ukuran potongan maksimum 3, misalnya, akan menghasilkan lebih banyak teluk yang diukir dari laut utama, dan laut # 1 akan dibagi menjadi dua bagian utara dan selatan. Ukuran laut minimum 20 akan menghasilkan laut tengah terbelah dua juga.