Files
GDMC-2024/world_maker/data_analysis.py
2024-06-12 00:56:55 +02:00

182 lines
6.0 KiB
Python

import World
from PIL import Image
from PIL import ImageFilter
import numpy as np
import networkx as nx
from scipy import ndimage
from scipy.ndimage import gaussian_gradient_magnitude
from scipy.ndimage import label
from Skeleton import Skeleton
def get_data(world: World):
heightmap, watermap, treemap = world.getData()
heightmap.save('./data/heightmap.png')
watermap.save('./data/watermap.png')
treemap.save('./data/treemap.png')
return heightmap, watermap, treemap
def filter_inverse(image: Image) -> Image:
"""
Invert the colors of an image.
Args:
image (image): image to filter
"""
return Image.fromarray(np.invert(np.array(image)))
def filter_sobel(image) -> Image:
"""
Edge detection algorithms from an image.
Args:
image (image): image to filter
"""
# Open the image
if isinstance(image, str):
image = Image.open(image).convert('RGB')
img = np.array(image).astype(np.uint8)
# Apply gray scale
gray_img = np.round(
0.299 * img[:, :, 0] + 0.587 * img[:, :, 1] + 0.114 * img[:, :, 2]
).astype(np.uint8)
# Sobel Operator
h, w = gray_img.shape
# define filters
horizontal = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]]) # s2
vertical = np.array([[-1, -2, -1], [0, 0, 0], [1, 2, 1]]) # s1
# define images with 0s
newhorizontalImage = np.zeros((h, w))
newverticalImage = np.zeros((h, w))
newgradientImage = np.zeros((h, w))
# offset by 1
for i in range(1, h - 1):
for j in range(1, w - 1):
horizontalGrad = (
(horizontal[0, 0] * gray_img[i - 1, j - 1])
+ (horizontal[0, 1] * gray_img[i - 1, j])
+ (horizontal[0, 2] * gray_img[i - 1, j + 1])
+ (horizontal[1, 0] * gray_img[i, j - 1])
+ (horizontal[1, 1] * gray_img[i, j])
+ (horizontal[1, 2] * gray_img[i, j + 1])
+ (horizontal[2, 0] * gray_img[i + 1, j - 1])
+ (horizontal[2, 1] * gray_img[i + 1, j])
+ (horizontal[2, 2] * gray_img[i + 1, j + 1])
)
newhorizontalImage[i - 1, j - 1] = abs(horizontalGrad)
verticalGrad = (
(vertical[0, 0] * gray_img[i - 1, j - 1])
+ (vertical[0, 1] * gray_img[i - 1, j])
+ (vertical[0, 2] * gray_img[i - 1, j + 1])
+ (vertical[1, 0] * gray_img[i, j - 1])
+ (vertical[1, 1] * gray_img[i, j])
+ (vertical[1, 2] * gray_img[i, j + 1])
+ (vertical[2, 0] * gray_img[i + 1, j - 1])
+ (vertical[2, 1] * gray_img[i + 1, j])
+ (vertical[2, 2] * gray_img[i + 1, j + 1])
)
newverticalImage[i - 1, j - 1] = abs(verticalGrad)
# Edge Magnitude
mag = np.sqrt(pow(horizontalGrad, 2.0) + pow(verticalGrad, 2.0))
newgradientImage[i - 1, j - 1] = mag
image = Image.fromarray(newgradientImage)
image = image.convert("L")
return image
def filter_smooth(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 radius: Radius of the Gaussian blur.
Returns:
image: black or white image, with black as flat areas to be skeletonized
"""
if isinstance(image, str):
image = Image.open(image)
# image = image.filter(ImageFilter.SMOOTH_MORE)
# image = image.filter(ImageFilter.SMOOTH_MORE)
# image = image.filter(ImageFilter.SMOOTH_MORE)
image = image.convert('L')
image = image.filter(ImageFilter.GaussianBlur(radius))
array = np.array(image)
bool_array = array > 7
# bool_array = ndimage.binary_opening(bool_array, structure=np.ones((3,3)), iterations=1)
# bool_array = ndimage.binary_closing(bool_array, structure=np.ones((3,3)), iterations=1)
# bool_array = ndimage.binary_opening(bool_array, structure=np.ones((5,5)), iterations=1)
# bool_array = ndimage.binary_closing(bool_array, structure=np.ones((5,5)), iterations=1)
# bool_array = ndimage.binary_opening(bool_array, structure=np.ones((7,7)), iterations=1)
# bool_array = ndimage.binary_closing(bool_array, structure=np.ones((7,7)), iterations=1)
return Image.fromarray(bool_array)
def remove_water_from_map(image: Image) -> Image:
watermap = Image.open('./data/watermap.png').convert('L')
array_heightmap = np.array(image)
array_watermap = np.array(watermap)
mask = array_watermap == 255
array_heightmap[mask] = 0
result_image = Image.fromarray(array_heightmap)
return result_image
def group_map(image1: Image, image2: Image) -> Image:
array1 = np.array(image1)
array2 = np.array(image2)
mask = array1 == 255
array2[mask] = 255
result_image = Image.fromarray(array2)
return result_image
def highway_map() -> Image:
smooth_sobel = filter_smooth("./data/sobelmap.png", 1)
inverse_sobel = filter_inverse(smooth_sobel)
sobel_no_water = remove_water_from_map(inverse_sobel)
sobel_no_water.save("./data/test.png")
array = np.array(sobel_no_water)
array = ndimage.binary_erosion(array, iterations=10)
array = ndimage.binary_dilation(array, iterations=5)
image = Image.fromarray(array)
smooth_image = filter_smooth(image, 5)
array = np.array(smooth_image)
array = ndimage.binary_erosion(array, iterations=17)
image = Image.fromarray(array)
smooth_image = filter_smooth(image, 6)
array = np.array(smooth_image)
array = ndimage.binary_dilation(array, iterations=3)
image = Image.fromarray(array)
image.save('./data/highwaymap.png')
return image
def skeletonnize_map(map: Image):
skeleton = Skeleton()
image_array = np.array(map)
skeleton.setSkeleton(image_array)
skeleton.parseGraph()
heightmap_skeleton, roadsArea = skeleton.map()
heightmap_skeleton.save('./data/skeleton.png')
roadsArea.save('./data/roads.png')