Skeleton highway
@@ -63,15 +63,15 @@ class City:
|
|||||||
"""
|
"""
|
||||||
min_distance = point.distance_to(self.districts[index_district].center_expend)
|
min_distance = point.distance_to(self.districts[index_district].center_expend)
|
||||||
index_district_chosen = index_district
|
index_district_chosen = index_district
|
||||||
for i in range(index_district + 1, len(self.districts)):
|
for index in range(index_district + 1, len(self.districts)):
|
||||||
if point in self.districts[i].area_expend:
|
if point in self.districts[index].area_expend:
|
||||||
distance = point.distance_to(self.districts[i].center_expend)
|
distance = point.distance_to(self.districts[index].center_expend)
|
||||||
if distance < min_distance:
|
if distance < min_distance:
|
||||||
min_distance = distance
|
min_distance = distance
|
||||||
self.districts[index_district_chosen].area_expend.remove(point)
|
self.districts[index_district_chosen].area_expend.remove(point)
|
||||||
index_district_chosen = i
|
index_district_chosen = index
|
||||||
else:
|
else:
|
||||||
self.districts[i].area_expend.remove(point)
|
self.districts[index].area_expend.remove(point)
|
||||||
self.districts[index_district_chosen].area.append(point)
|
self.districts[index_district_chosen].area.append(point)
|
||||||
self.districts[index_district_chosen].area_expend_from_point.append(point)
|
self.districts[index_district_chosen].area_expend_from_point.append(point)
|
||||||
self.districts[index_district_chosen].area_expend.remove(point)
|
self.districts[index_district_chosen].area_expend.remove(point)
|
||||||
@@ -106,8 +106,8 @@ class City:
|
|||||||
"""
|
"""
|
||||||
width, height = len(self.map_data[0]), len(self.map_data)
|
width, height = len(self.map_data[0]), len(self.map_data)
|
||||||
img = Image.new('RGB', (width, height))
|
img = Image.new('RGB', (width, height))
|
||||||
colors = {i: (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
|
colors = {id_district: (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
|
||||||
for i in range(1, len(self.districts) + 1)}
|
for id_district in range(1, len(self.districts) + 1)}
|
||||||
|
|
||||||
for y in range(height):
|
for y in range(height):
|
||||||
for x in range(width):
|
for x in range(width):
|
||||||
|
|||||||
@@ -10,18 +10,18 @@ class District:
|
|||||||
area_expend_from_point (list): The list of positions from which the district can expand.
|
area_expend_from_point (list): The list of positions from which the district can expand.
|
||||||
area_expend (list): The list of positions to which the district will maybe expand.
|
area_expend (list): The list of positions to which the district will maybe expand.
|
||||||
"""
|
"""
|
||||||
def __init__(self, tile_id: int, center: Position, type: str = ""):
|
def __init__(self, tile_id: int, center: Position, district_type: str = ""):
|
||||||
"""
|
"""
|
||||||
The constructor for the District class.
|
The constructor for the District class.
|
||||||
|
|
||||||
:param tile_id: Unique id of the district (Must be greater than 0)
|
:param tile_id: Unique id of the district (Must be greater than 0)
|
||||||
:param center: The center position from which the district expands.
|
:param center: The center position from which the district expands.
|
||||||
:param type: The type of the district (Forest, City, Mountain, Villa)
|
:param district_type: The type of the district (Forest, City, Mountain, Villa)
|
||||||
"""
|
"""
|
||||||
if tile_id <= 0:
|
if tile_id <= 0:
|
||||||
raise ValueError("Tile id must be greater than 0")
|
raise ValueError("Tile id must be greater than 0")
|
||||||
self.tile_id = tile_id
|
self.tile_id = tile_id
|
||||||
self.type = type
|
self.type = district_type
|
||||||
self.center_expend = center
|
self.center_expend = center
|
||||||
self.area = [center]
|
self.area = [center]
|
||||||
self.area_expend_from_point = [center]
|
self.area_expend_from_point = [center]
|
||||||
|
|||||||
@@ -1,44 +1,40 @@
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
import skan
|
#import skan
|
||||||
from skimage.morphology import skeletonize
|
from skimage.morphology import skeletonize
|
||||||
from skan.csr import skeleton_to_csgraph
|
from skan.csr import skeleton_to_csgraph
|
||||||
from collections import Counter
|
from collections import Counter
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
import random
|
import random
|
||||||
|
|
||||||
from gdpc import Editor
|
|
||||||
|
|
||||||
|
|
||||||
class Skeleton:
|
class Skeleton:
|
||||||
def __init__(self):
|
def __init__(self, data: np.ndarray = None):
|
||||||
self.lines = []
|
self.lines = []
|
||||||
self.intersections = []
|
self.intersections = []
|
||||||
self.centers = []
|
self.centers = []
|
||||||
self.graph = []
|
|
||||||
self.coordinates = []
|
self.coordinates = []
|
||||||
|
self.graph = None
|
||||||
|
if data is not None:
|
||||||
|
self.set_skeleton(data)
|
||||||
|
|
||||||
def setSkeleton(self, data):
|
def set_skeleton(self, data: np.ndarray):
|
||||||
binary_skeleton = skeletonize(data)
|
binary_skeleton = skeletonize(data, method="lee")
|
||||||
|
|
||||||
graph, coordinates = skeleton_to_csgraph(binary_skeleton)
|
graph, coordinates = skeleton_to_csgraph(binary_skeleton)
|
||||||
self.graph = graph.tocoo()
|
self.graph = graph.tocoo()
|
||||||
|
|
||||||
# List of lists. Inverted coordinates.
|
# List of lists. Inverted coordinates.
|
||||||
coordinates = list(coordinates)
|
coordinates = list(coordinates)
|
||||||
print(coordinates)
|
# print(coordinates)
|
||||||
for i in range(len(coordinates)):
|
for i in range(len(coordinates)):
|
||||||
coordinates[i] = list(coordinates[i])
|
coordinates[i] = list(coordinates[i])
|
||||||
|
# print(coordinates)
|
||||||
print(coordinates)
|
|
||||||
coordinates_final = []
|
|
||||||
|
|
||||||
for i in range(len(coordinates[0])):
|
for i in range(len(coordinates[0])):
|
||||||
print((coordinates[0][i], coordinates[1][i], coordinates[2][i]))
|
# print((coordinates[0][i], coordinates[1][i], coordinates[2][i]))
|
||||||
coordinates_final.append((coordinates[0][i], coordinates[1][i], coordinates[2][i]))
|
self.coordinates.append((coordinates[0][i], coordinates[1][i], coordinates[2][i]))
|
||||||
|
|
||||||
self.coordinates = coordinates_final
|
def find_next_elements(self, key: str) -> list:
|
||||||
|
|
||||||
def findNextElements(self, key):
|
|
||||||
"""Find the very nearest elements"""
|
"""Find the very nearest elements"""
|
||||||
|
|
||||||
line = []
|
line = []
|
||||||
@@ -51,51 +47,50 @@ class Skeleton:
|
|||||||
line.append(self.graph.col[indices[i]])
|
line.append(self.graph.col[indices[i]])
|
||||||
return line
|
return line
|
||||||
|
|
||||||
def findLine(self, key):
|
def find_line(self, key: str):
|
||||||
nextKeys = self.findNextElements(key)
|
next_keys = self.find_next_elements(key)
|
||||||
|
|
||||||
if len(nextKeys) >= 3: # Intersections.
|
if len(next_keys) >= 3: # Intersections.
|
||||||
return nextKeys
|
return next_keys
|
||||||
|
|
||||||
if len(nextKeys) == 2 or len(nextKeys) == 1: # In line or endpoints.
|
if len(next_keys) == 2 or len(next_keys) == 1: # In line or endpoints.
|
||||||
line = []
|
line = [key]
|
||||||
line.append(key)
|
line.insert(0, next_keys[0])
|
||||||
line.insert(0, nextKeys[0])
|
if len(next_keys) == 2:
|
||||||
if len(nextKeys) == 2:
|
line.insert(len(line), next_keys[1])
|
||||||
line.insert(len(line), nextKeys[1])
|
|
||||||
|
|
||||||
nextKeys = line[0], line[-1]
|
next_keys = line[0], line[-1]
|
||||||
|
|
||||||
while len(nextKeys) == 2 or len(nextKeys) == 1:
|
while len(next_keys) == 2 or len(next_keys) == 1:
|
||||||
extremity = []
|
extremity = []
|
||||||
for key in nextKeys:
|
for key in next_keys:
|
||||||
nextKeys = self.findNextElements(key)
|
next_keys = self.find_next_elements(key)
|
||||||
|
|
||||||
if len(nextKeys) <= 2:
|
if len(next_keys) <= 2:
|
||||||
# Add the neighbors that is not already in the line.
|
# Add the neighbors that is not already in the line.
|
||||||
for element in nextKeys:
|
for element in next_keys:
|
||||||
if element not in line:
|
if element not in line:
|
||||||
extremity.append(element)
|
extremity.append(element)
|
||||||
line.append(element)
|
line.append(element)
|
||||||
|
|
||||||
if len(nextKeys) >= 3:
|
if len(next_keys) >= 3:
|
||||||
# Add the intersection only.
|
# Add the intersection only.
|
||||||
extremity.append(key)
|
extremity.append(key)
|
||||||
|
|
||||||
nextKeys = []
|
next_keys = []
|
||||||
for key in extremity:
|
for key in extremity:
|
||||||
ends = self.findNextElements(key)
|
ends = self.find_next_elements(key)
|
||||||
if len(ends) == 2:
|
if len(ends) == 2:
|
||||||
nextKeys.append(key)
|
next_keys.append(key)
|
||||||
return line
|
return line
|
||||||
|
|
||||||
def parseGraph(self):
|
def parse_graph(self, parse_orphan: bool = False):
|
||||||
for key, value in sorted(
|
for key, value in sorted(
|
||||||
Counter(self.graph.row).items(), key=lambda kv: kv[1], reverse=True
|
Counter(self.graph.row).items(), key=lambda kv: kv[1], reverse=True
|
||||||
):
|
):
|
||||||
# Start from the biggest intersections.
|
# Start from the biggest intersections.
|
||||||
if value != 2: # We don't want to be in the middle of a line.
|
if value != 2: # We don't want to be in the middle of a line.
|
||||||
line = self.findLine(key)
|
line = self.find_line(key)
|
||||||
|
|
||||||
# We have now all the connected points if it's an
|
# We have now all the connected points if it's an
|
||||||
# intersection. We need to find the line.
|
# intersection. We need to find the line.
|
||||||
@@ -105,34 +100,44 @@ class Skeleton:
|
|||||||
self.centers.append(key)
|
self.centers.append(key)
|
||||||
self.intersections.append(line)
|
self.intersections.append(line)
|
||||||
for i in line:
|
for i in line:
|
||||||
line = self.findLine(i)
|
line = self.find_line(i)
|
||||||
|
|
||||||
if i in line:
|
if i in line:
|
||||||
# The key is inside the result : it's a line.
|
# The key is inside the result : it's a line.
|
||||||
alreadyInside = False
|
already_inside = False
|
||||||
for l in self.lines:
|
for l in self.lines:
|
||||||
# Verification if not already inside.
|
# Verification if not already inside.
|
||||||
if Counter(l) == Counter(line):
|
if Counter(l) == Counter(line):
|
||||||
alreadyInside = True
|
already_inside = True
|
||||||
# print(line, "inside", lines)
|
# print(line, "inside", lines)
|
||||||
|
|
||||||
if alreadyInside == False:
|
if not already_inside:
|
||||||
self.lines.append(line)
|
self.lines.append(line)
|
||||||
else:
|
else:
|
||||||
# The key is not inside the result, it's an
|
# The key is not inside the result, it's an
|
||||||
# intersection directly connected to the key.
|
# intersection directly connected to the key.
|
||||||
line = [key, i]
|
line = [key, i]
|
||||||
alreadyInside = False
|
already_inside = False
|
||||||
for l in self.lines:
|
for l in self.lines:
|
||||||
# Verification if not already inside.
|
# Verification if not already inside.
|
||||||
if Counter(l) == Counter(line):
|
if Counter(l) == Counter(line):
|
||||||
alreadyInside = True
|
already_inside = True
|
||||||
# print(line, "inside", lines)
|
# print(line, "inside", lines)
|
||||||
|
|
||||||
if alreadyInside == False:
|
if not already_inside:
|
||||||
|
self.lines.append(line)
|
||||||
|
elif value == 2 and parse_orphan:
|
||||||
|
line = self.find_line(key)
|
||||||
|
already_inside = False
|
||||||
|
for l in self.lines:
|
||||||
|
# Verification if not already inside.
|
||||||
|
if Counter(l) == Counter(line):
|
||||||
|
already_inside = True
|
||||||
|
|
||||||
|
if not already_inside:
|
||||||
self.lines.append(line)
|
self.lines.append(line)
|
||||||
|
|
||||||
def map(self):
|
def map(self) -> Image:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
Generate an image to visualize 2D path of the skeleton.
|
Generate an image to visualize 2D path of the skeleton.
|
||||||
@@ -140,17 +145,17 @@ class Skeleton:
|
|||||||
Returns:
|
Returns:
|
||||||
image: 2D path of the skeleton on top of the heightmap.
|
image: 2D path of the skeleton on top of the heightmap.
|
||||||
"""
|
"""
|
||||||
editor = Editor()
|
# editor = Editor()
|
||||||
|
|
||||||
buildArea = editor.getBuildArea()
|
# buildArea = editor.getBuildArea()
|
||||||
buildRect = buildArea.toRect()
|
# buildRect = buildArea.toRect()
|
||||||
xzStart = buildRect.begin
|
# xzStart = buildRect.begin
|
||||||
xzDistance = (max(buildRect.end[0], buildRect.begin[0]) - min(buildRect.end[0], buildRect.begin[0]),
|
# xzDistance = (max(buildRect.end[0], buildRect.begin[0]) - min(buildRect.end[0], buildRect.begin[0]),
|
||||||
max(buildRect.end[1], buildRect.begin[1]) - min(buildRect.end[1], buildRect.begin[1]))
|
# max(buildRect.end[1], buildRect.begin[1]) - min(buildRect.end[1], buildRect.begin[1]))
|
||||||
|
|
||||||
heightmap = Image.open("data/heightmap.png").convert('RGB')
|
heightmap = Image.open("data/heightmap.png").convert('RGB')
|
||||||
roadsArea = Image.new("L", xzDistance, 0)
|
# roadsArea = Image.new("L", xzDistance, 0)
|
||||||
width, height = heightmap.size
|
# width, height = heightmap.size
|
||||||
|
|
||||||
# Lines
|
# Lines
|
||||||
for i in range(len(self.lines)):
|
for i in range(len(self.lines)):
|
||||||
@@ -158,7 +163,7 @@ class Skeleton:
|
|||||||
|
|
||||||
for j in range(len(self.lines[i])):
|
for j in range(len(self.lines[i])):
|
||||||
z = self.coordinates[self.lines[i][j]][0]
|
z = self.coordinates[self.lines[i][j]][0]
|
||||||
y = self.coordinates[self.lines[i][j]][1]
|
# y = self.coordinates[self.lines[i][j]][1]
|
||||||
x = self.coordinates[self.lines[i][j]][2]
|
x = self.coordinates[self.lines[i][j]][2]
|
||||||
|
|
||||||
heightmap.putpixel(
|
heightmap.putpixel(
|
||||||
@@ -169,26 +174,26 @@ class Skeleton:
|
|||||||
(r + j, g + j, b + j),
|
(r + j, g + j, b + j),
|
||||||
)
|
)
|
||||||
|
|
||||||
roadsArea.putpixel(
|
# roadsArea.putpixel(
|
||||||
(
|
# (
|
||||||
int(z),
|
# int(z),
|
||||||
int(x),
|
# int(x),
|
||||||
),
|
# ),
|
||||||
(255),
|
# (255),
|
||||||
)
|
# )
|
||||||
|
|
||||||
# Centers
|
# Centers
|
||||||
for i in range(len(self.centers)):
|
for i in range(len(self.centers)):
|
||||||
print(self.coordinates[self.centers[i]])
|
# print(self.coordinates[self.centers[i]])
|
||||||
heightmap.putpixel(
|
heightmap.putpixel(
|
||||||
(int(self.coordinates[self.centers[i]][0]), int(self.coordinates[self.centers[i]][2])),
|
(int(self.coordinates[self.centers[i]][0]), int(self.coordinates[self.centers[i]][2])),
|
||||||
(255, 255, 0),
|
(255, 255, 0),
|
||||||
)
|
)
|
||||||
|
|
||||||
roadsArea.putpixel(
|
# roadsArea.putpixel(
|
||||||
(int(self.coordinates[self.centers[i]][0]), int(self.coordinates[self.centers[i]][2])),
|
# (int(self.coordinates[self.centers[i]][0]), int(self.coordinates[self.centers[i]][2])),
|
||||||
(255),
|
# (255),
|
||||||
)
|
# )
|
||||||
|
|
||||||
# # Intersections
|
# # Intersections
|
||||||
# for i in range(len(self.intersections)):
|
# for i in range(len(self.intersections)):
|
||||||
@@ -202,4 +207,4 @@ class Skeleton:
|
|||||||
# (255, 0, 255),
|
# (255, 0, 255),
|
||||||
# )
|
# )
|
||||||
|
|
||||||
return heightmap, roadsArea
|
return heightmap # , roadsArea
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ class World:
|
|||||||
number = 0
|
number = 0
|
||||||
for i in range(-1, 2):
|
for i in range(-1, 2):
|
||||||
for j in range(-1, 2):
|
for j in range(-1, 2):
|
||||||
if (i != 0 or j != 0):
|
if i != 0 or j != 0:
|
||||||
if (0 <= x + i < xzDistance[0]) and (0 <= z + j < xzDistance[1]):
|
if (0 <= x + i < xzDistance[0]) and (0 <= z + j < xzDistance[1]):
|
||||||
k = heightmapData[x + i][z + j] - 1
|
k = heightmapData[x + i][z + j] - 1
|
||||||
|
|
||||||
@@ -160,10 +160,10 @@ class World:
|
|||||||
print(average, "average")
|
print(average, "average")
|
||||||
heightmap.putpixel((x, z), (average, average, average))
|
heightmap.putpixel((x, z), (average, average, average))
|
||||||
|
|
||||||
if ((biome in waterBiomes) or (block.id in waterBlocks)):
|
if (biome in waterBiomes) or (block.id in waterBlocks):
|
||||||
watermap.putpixel((x, z), (255))
|
watermap.putpixel((x, z), 255)
|
||||||
else:
|
else:
|
||||||
watermap.putpixel((x, z), (0))
|
watermap.putpixel((x, z), 0)
|
||||||
|
|
||||||
self.addBlocks([Block((xzStart[0] + x, 100, xzStart[1] + z), block)]) # y set to 100 for 2D
|
self.addBlocks([Block((xzStart[0] + x, 100, xzStart[1] + z), block)]) # y set to 100 for 2D
|
||||||
|
|
||||||
@@ -190,7 +190,7 @@ class World:
|
|||||||
for y in range(self.length_y):
|
for y in range(self.length_y):
|
||||||
binaryImage[x].append([])
|
binaryImage[x].append([])
|
||||||
for z in range(self.length_z):
|
for z in range(self.length_z):
|
||||||
if (self.volume[x][y][z] != None):
|
if self.volume[x][y][z] != None:
|
||||||
binaryImage[x][y].append(True)
|
binaryImage[x][y].append(True)
|
||||||
else:
|
else:
|
||||||
binaryImage[x][y].append(False)
|
binaryImage[x][y].append(False)
|
||||||
@@ -222,7 +222,7 @@ class World:
|
|||||||
for x in range(0, xzDistance[0]):
|
for x in range(0, xzDistance[0]):
|
||||||
for z in range(0, xzDistance[1]):
|
for z in range(0, xzDistance[1]):
|
||||||
y = heightmapData[x][z] - 1
|
y = heightmapData[x][z] - 1
|
||||||
if mask.getpixel((x, z)) == (255):
|
if mask.getpixel((x, z)) == 255:
|
||||||
self.removeBlock((x, 100, z)) # y set to 100 for 2D
|
self.removeBlock((x, 100, z)) # y set to 100 for 2D
|
||||||
|
|
||||||
def simplifyVolume(self):
|
def simplifyVolume(self):
|
||||||
|
|||||||
0
world_maker/data/.gitignore
vendored
Normal file
|
Before Width: | Height: | Size: 7.1 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 225 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 18 KiB |
BIN
world_maker/data/negative_sobel_water_map.png
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
world_maker/data/skeleton_highway.png
Normal file
|
After Width: | Height: | Size: 263 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 283 KiB |
|
Before Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 302 KiB |
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 12 KiB |
@@ -1,12 +1,10 @@
|
|||||||
import World
|
import World
|
||||||
from PIL import Image
|
from PIL import Image, ImageFilter
|
||||||
from PIL import ImageFilter
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import networkx as nx
|
|
||||||
from scipy import ndimage
|
from scipy import ndimage
|
||||||
from scipy.ndimage import gaussian_gradient_magnitude
|
|
||||||
from scipy.ndimage import label
|
|
||||||
from Skeleton import Skeleton
|
from Skeleton import Skeleton
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
|
|
||||||
def get_data(world: World):
|
def get_data(world: World):
|
||||||
heightmap, watermap, treemap = world.getData()
|
heightmap, watermap, treemap = world.getData()
|
||||||
@@ -16,7 +14,13 @@ def get_data(world: World):
|
|||||||
return heightmap, watermap, treemap
|
return heightmap, watermap, treemap
|
||||||
|
|
||||||
|
|
||||||
def filter_inverse(image: Image) -> Image:
|
def handle_import_image(image: Union[str, Image]) -> Image:
|
||||||
|
if isinstance(image, str):
|
||||||
|
return Image.open(image)
|
||||||
|
return image
|
||||||
|
|
||||||
|
|
||||||
|
def filter_negative(image: Image) -> Image:
|
||||||
"""
|
"""
|
||||||
Invert the colors of an image.
|
Invert the colors of an image.
|
||||||
|
|
||||||
@@ -26,7 +30,7 @@ def filter_inverse(image: Image) -> Image:
|
|||||||
return Image.fromarray(np.invert(np.array(image)))
|
return Image.fromarray(np.invert(np.array(image)))
|
||||||
|
|
||||||
|
|
||||||
def filter_sobel(image) -> Image:
|
def filter_sobel(image: Union[str, Image]) -> Image:
|
||||||
"""
|
"""
|
||||||
Edge detection algorithms from an image.
|
Edge detection algorithms from an image.
|
||||||
|
|
||||||
@@ -35,8 +39,7 @@ def filter_sobel(image) -> Image:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
# Open the image
|
# Open the image
|
||||||
if isinstance(image, str):
|
image = handle_import_image(image).convert('RGB')
|
||||||
image = Image.open(image).convert('RGB')
|
|
||||||
|
|
||||||
img = np.array(image).astype(np.uint8)
|
img = np.array(image).astype(np.uint8)
|
||||||
|
|
||||||
@@ -97,7 +100,7 @@ def filter_sobel(image) -> Image:
|
|||||||
return image
|
return image
|
||||||
|
|
||||||
|
|
||||||
def filter_smooth(image, radius: int = 3):
|
def filter_smooth(image: Union[str, Image], radius: int = 3):
|
||||||
"""
|
"""
|
||||||
:param image: white and black image representing the derivative of the terrain (sobel), where black is flat and white is very steep.
|
:param image: white and black image representing the derivative of the terrain (sobel), where black is flat and white is very steep.
|
||||||
:param radius: Radius of the Gaussian blur.
|
:param radius: Radius of the Gaussian blur.
|
||||||
@@ -106,8 +109,7 @@ def filter_smooth(image, radius: int = 3):
|
|||||||
image: black or white image, with black as flat areas to be skeletonized
|
image: black or white image, with black as flat areas to be skeletonized
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if isinstance(image, str):
|
image = handle_import_image(image)
|
||||||
image = Image.open(image)
|
|
||||||
|
|
||||||
# image = image.filter(ImageFilter.SMOOTH_MORE)
|
# image = image.filter(ImageFilter.SMOOTH_MORE)
|
||||||
# image = image.filter(ImageFilter.SMOOTH_MORE)
|
# image = image.filter(ImageFilter.SMOOTH_MORE)
|
||||||
@@ -128,7 +130,8 @@ def filter_smooth(image, radius: int = 3):
|
|||||||
return Image.fromarray(bool_array)
|
return Image.fromarray(bool_array)
|
||||||
|
|
||||||
|
|
||||||
def remove_water_from_map(image: Image) -> Image:
|
def remove_water_from_map(image: Union[str, Image]) -> Image:
|
||||||
|
image = handle_import_image(image)
|
||||||
watermap = Image.open('./data/watermap.png').convert('L')
|
watermap = Image.open('./data/watermap.png').convert('L')
|
||||||
|
|
||||||
array_heightmap = np.array(image)
|
array_heightmap = np.array(image)
|
||||||
@@ -141,42 +144,66 @@ def remove_water_from_map(image: Image) -> Image:
|
|||||||
return result_image
|
return result_image
|
||||||
|
|
||||||
|
|
||||||
def group_map(image1: Image, image2: Image) -> Image:
|
def group_map(image1: Union[str, Image], image2: Union[str, Image]) -> Image:
|
||||||
|
image1 = handle_import_image(image1)
|
||||||
|
image2 = handle_import_image(image2)
|
||||||
|
|
||||||
array1 = np.array(image1)
|
array1 = np.array(image1)
|
||||||
array2 = np.array(image2)
|
array2 = np.array(image2)
|
||||||
|
|
||||||
mask = array1 == 255
|
mask = array1 == 255
|
||||||
array2[mask] = 255
|
array2[mask] = 255
|
||||||
|
|
||||||
result_image = Image.fromarray(array2)
|
return Image.fromarray(array2)
|
||||||
return result_image
|
|
||||||
|
|
||||||
|
def filter_smooth_array(array: np.ndarray, radius: int = 3) -> np.ndarray:
|
||||||
|
image = Image.fromarray(array)
|
||||||
|
smooth_image = filter_smooth(image, radius)
|
||||||
|
array = np.array(smooth_image)
|
||||||
|
return array
|
||||||
|
|
||||||
|
|
||||||
def highway_map() -> Image:
|
def highway_map() -> Image:
|
||||||
smooth_sobel = filter_smooth("./data/sobelmap.png", 1)
|
smooth_sobel = filter_smooth("./data/sobelmap.png", 1)
|
||||||
inverse_sobel = filter_inverse(smooth_sobel)
|
inverse_sobel = filter_negative(smooth_sobel)
|
||||||
sobel_no_water = remove_water_from_map(inverse_sobel)
|
sobel_no_water = remove_water_from_map(inverse_sobel)
|
||||||
sobel_no_water.save("./data/test.png")
|
sobel_no_water.save("./data/negative_sobel_water_map.png")
|
||||||
array = np.array(sobel_no_water)
|
array = np.array(sobel_no_water)
|
||||||
array = ndimage.binary_erosion(array, iterations=10)
|
array = ndimage.binary_erosion(array, iterations=10)
|
||||||
array = ndimage.binary_dilation(array, iterations=5)
|
array = ndimage.binary_dilation(array, iterations=5)
|
||||||
image = Image.fromarray(array)
|
array = filter_smooth_array(array, 5)
|
||||||
smooth_image = filter_smooth(image, 5)
|
|
||||||
array = np.array(smooth_image)
|
|
||||||
array = ndimage.binary_erosion(array, iterations=17)
|
array = ndimage.binary_erosion(array, iterations=17)
|
||||||
image = Image.fromarray(array)
|
array = filter_smooth_array(array, 6)
|
||||||
smooth_image = filter_smooth(image, 6)
|
|
||||||
array = np.array(smooth_image)
|
|
||||||
array = ndimage.binary_dilation(array, iterations=3)
|
array = ndimage.binary_dilation(array, iterations=3)
|
||||||
image = Image.fromarray(array)
|
image = Image.fromarray(array)
|
||||||
image.save('./data/highwaymap.png')
|
image.save('./data/highwaymap.png')
|
||||||
return image
|
return image
|
||||||
|
|
||||||
def skeletonnize_map(map: Image):
|
|
||||||
skeleton = Skeleton()
|
def create_volume(surface: np.ndarray, heightmap: np.ndarray, make_it_flat: bool = False) -> np.ndarray:
|
||||||
image_array = np.array(map)
|
volume = np.full((len(surface), 255, len(surface[0])), False)
|
||||||
skeleton.setSkeleton(image_array)
|
for z in range(len(surface)):
|
||||||
skeleton.parseGraph()
|
for x in range(len(surface[0])):
|
||||||
heightmap_skeleton, roadsArea = skeleton.map()
|
if not make_it_flat:
|
||||||
heightmap_skeleton.save('./data/skeleton.png')
|
volume[x][heightmap[z][x]][z] = surface[z][x]
|
||||||
roadsArea.save('./data/roads.png')
|
else:
|
||||||
|
volume[x][0][z] = surface[z][x]
|
||||||
|
return volume
|
||||||
|
|
||||||
|
|
||||||
|
def convert_2D_to_3D(image: Union[str, Image], make_it_flat: bool = False) -> np.ndarray:
|
||||||
|
image = handle_import_image(image)
|
||||||
|
heightmap = Image.open('./data/heightmap.png').convert('L')
|
||||||
|
heightmap = np.array(heightmap)
|
||||||
|
surface = np.array(image)
|
||||||
|
volume = create_volume(surface, heightmap, make_it_flat)
|
||||||
|
return volume
|
||||||
|
|
||||||
|
|
||||||
|
def skeleton_highway_map(map: Union[str, Image]):
|
||||||
|
image_array = convert_2D_to_3D(map, True)
|
||||||
|
skeleton = Skeleton(image_array)
|
||||||
|
skeleton.parse_graph(True)
|
||||||
|
heightmap_skeleton = skeleton.map()
|
||||||
|
heightmap_skeleton.save('./data/skeleton_highway.png')
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import World
|
import World
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
from data_analysis import get_data, highway_map, filter_sobel, skeletonnize_map
|
from data_analysis import get_data, highway_map, filter_sobel, skeleton_highway_map
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
#world = World.World()
|
#world = World.World()
|
||||||
#heightmap, watermap, treemap = get_data(world)
|
#heightmap, watermap, treemap = get_data(world)
|
||||||
#filter_sobel("./data/heightmap.png").save('./data/sobelmap.png')
|
filter_sobel("./data/heightmap.png").save('./data/sobelmap.png')
|
||||||
highway_map()
|
highway_map()
|
||||||
skeletonnize_map(Image.open('./data/highwaymap.png'))
|
skeleton_highway_map(Image.open('./data/highwaymap.png'))
|
||||||
|
|||||||