Further fine tuning to rendering and layering, added subtle details to different kinds of buildings for more realism

This commit is contained in:
Marcus Str. 2024-10-12 21:18:39 +02:00
parent 265197d295
commit 817d65639d
21 changed files with 103 additions and 41 deletions

View File

@ -148,6 +148,8 @@ mstr_ortho_layers = [
("highway", "living_street", 12), ("highway", "living_street", 12),
("waterway", "river", 10), ("waterway", "river", 10),
("waterway", "stream", 2), ("waterway", "stream", 2),
("amenity", "parking", "amenity", "parking"),
("amenity", "school", "amenity", "school"),
("leisure", "nature_reserve", "landuse", "forest"), ("leisure", "nature_reserve", "landuse", "forest"),
("landuse", "forest", "landuse", "forest"), ("landuse", "forest", "landuse", "forest"),
("natural", "wood", "natural", "wood"), ("natural", "wood", "natural", "wood"),
@ -165,8 +167,6 @@ mstr_ortho_layers = [
("water", "pond", "natural", "water"), ("water", "pond", "natural", "water"),
("water", "river", "natural", "water"), ("water", "river", "natural", "water"),
("leisure", "swimming_pool", "natural", "water"), ("leisure", "swimming_pool", "natural", "water"),
("amenity", "parking", "amenity", "parking"),
("amenity", "school", "amenity", "school"),
("highway", "pedestrian", 4), ("highway", "pedestrian", 4),
# Z-Order 4 # Z-Order 4
("highway", "motorway", 32), ("highway", "motorway", 32),
@ -189,9 +189,9 @@ mstr_ortho_layers = [
("building", "terrace", "building", "industrial"), ("building", "terrace", "building", "industrial"),
("building", "hangar", "building", "industrial"), ("building", "hangar", "building", "industrial"),
("building", "school", "building", "common"), ("building", "school", "building", "common"),
("building", "kindergarten", "building", "kindergarten"), ("building", "kindergarten", "building", "kindergarten"),
("building", "public", "building", "public"), ("building", "public", "building", "public"),
("building", "commercial", "building", "commercial"), ("building", "commercial", "building", "commercial"),
("building", "yes", "building", "common"), ("building", "yes", "building", "common"),
("place", "sea", "natural", "sea"), ("place", "sea", "natural", "sea"),
("place", "ocean", "natural", "sea") ("place", "ocean", "natural", "sea")
@ -395,6 +395,15 @@ mstr_building_base_colors = [
] ]
# Base colors to add some details to all kinds of buildings
mstr_building_detail_colors = [
(136, 132, 86), # Some kind of moss
(136, 90, 86), # Some kind of rust or darkening
(154, 154, 154), # Other random details
(97, 97, 97) # Square or line details, alpha-blended
]
mstr_completion_colors = [ mstr_completion_colors = [
("+50+000", [ ("+50+000", [
(48,63,34), (48,63,34),

View File

@ -16,7 +16,7 @@ import glob
import os import os
from random import randrange from random import randrange
import random import random
from PIL import Image, ImageFilter, ImageDraw, ImagePath, ImageEnhance from PIL import Image, ImageFilter, ImageDraw
from defines import * from defines import *
from log import * from log import *
from tileinfo import * from tileinfo import *
@ -56,11 +56,6 @@ class mstr_layergen:
def set_latlng_folder(self, latlngfld): def set_latlng_folder(self, latlngfld):
self._latlngfld = latlngfld self._latlngfld = latlngfld
# Open DB
def open_db(self):
self._tiledb = mstr_tiledb(self._latitude, self._longitude, self._latlngfld)
self._tiledb.create_tables()
# Tile info object # Tile info object
def open_tile_info(self): def open_tile_info(self):
self._tileinfo = mstr_tileinfo(self._latitude, self._longitude, self._lat_number, self._lng_number, self._latlngfld) self._tileinfo = mstr_tileinfo(self._latitude, self._longitude, self._lat_number, self._lng_number, self._latlngfld)
@ -473,7 +468,8 @@ class mstr_layergen:
for x in range(self._imgsize): for x in range(self._imgsize):
tp = tree_pix[x,y] tp = tree_pix[x,y]
if tp[3] > 0: if tp[3] > 0:
sc = (0,0,0,180) rndshd = randrange(5, 210)
sc = (0,0,0,rndshd)
if x+8 < self._imgsize and y+5 < self._imgsize: if x+8 < self._imgsize and y+5 < self._imgsize:
shadow_pix[x+8,y+5] = sc shadow_pix[x+8,y+5] = sc
tree_shadow = tree_shadow.filter(ImageFilter.GaussianBlur(radius=2)) tree_shadow = tree_shadow.filter(ImageFilter.GaussianBlur(radius=2))
@ -547,18 +543,12 @@ class mstr_layergen:
if os.path.isfile(fn): if os.path.isfile(fn):
rsd = Image.open(fn) rsd = Image.open(fn)
rsd_pix = rsd.load() rsd_pix = rsd.load()
forest_layer = Image.new("RGBA", (self._imgsize, self._imgsize))
for_pix = forest_layer.load()
for y in range(self._imgsize): for y in range(self._imgsize):
for x in range(self._imgsize): for x in range(self._imgsize):
rpix = rsd_pix[x,y] rpix = rsd_pix[x,y]
lpix = layer_comp_pix[x,y] lpix = layer_comp_pix[x,y]
if rpix[3] > 0 and lpix[3] > 0: if rpix[3] > 0 and lpix[3] > 0:
for_pix[x,y] = (rpix[0], rpix[1], rpix[2], rpix[3]) layer_comp_pix[x,y] = (lpix[0], lpix[1], lpix[2], 255-rpix[3])
layer_comp.alpha_composite(forest_layer)
#if os.path.isfile(fn) == True:
# rsd = Image.open(fn)
# layer_comp.alpha_composite(rsd)
# Store layer # Store layer
if self._is_completion == False: if self._is_completion == False:
@ -612,20 +602,6 @@ class mstr_layergen:
shadow = shadow.filter(ImageFilter.GaussianBlur(radius=1.5)) shadow = shadow.filter(ImageFilter.GaussianBlur(radius=1.5))
"""
for y in range(self._imgsize-1):
for x in range(self._imgsize-1):
m = mask_pix[x,y]
shf_x = 0
shf_x = x + mstr_shadow_shift
if shf_x < self._imgsize:
a = mask_pix[x,y][3]
st = 0
st = random.uniform(0.45, mstr_shadow_strength)
ca = a * st
aa = int(ca)
shadow_pix[shf_x, y] = (0,0,0,aa)
"""
shadow.save(mstr_datafolder + "_cache/" + str(self._latitude) + "-" + str(self._lat_number) + "_" + str(self._longitude) + "-" + str(self._lng_number) + "_" + self._tag + "-" + self._value + "_layer_shadow.png") shadow.save(mstr_datafolder + "_cache/" + str(self._latitude) + "-" + str(self._lat_number) + "_" + str(self._longitude) + "-" + str(self._lng_number) + "_" + self._tag + "-" + self._value + "_layer_shadow.png")
mstr_msg("layergen", "Shadow layer completed") mstr_msg("layergen", "Shadow layer completed")
@ -638,14 +614,14 @@ class mstr_layergen:
ab=False ab=False
al=False al=False
layer_pix = layer_comp.load() # <- Just to be safe layer_pix = layer_comp.load() # <- Just to be safe
# Top scan # Top scan
for i in range(0, self._imgsize-1): for i in range(0, self._imgsize-1):
p = layer_pix[i,0] p = layer_pix[i,0]
if p[3] > 0: if p[3] > 0:
at=True at=True
break break
# Right scan # Right scan
for i in range(0, self._imgsize-1): for i in range(0, self._imgsize-1):
p = layer_pix[self._imgsize-1,i] p = layer_pix[self._imgsize-1,i]
@ -842,8 +818,8 @@ class mstr_layergen:
details = Image.new("RGBA", (self._imgsize, self._imgsize)) details = Image.new("RGBA", (self._imgsize, self._imgsize))
details_pix = details.load() details_pix = details.load()
layer_pix = layer_comp.load() layer_pix = layer_comp.load()
for y in range(self._imgsize-1): for y in range(self._imgsize):
for x in range(self._imgsize-1): for x in range(self._imgsize):
p = layer_pix[x,y] p = layer_pix[x,y]
if p[3] > 0: if p[3] > 0:
shf_x = x+randrange(1, 16) shf_x = x+randrange(1, 16)
@ -859,6 +835,25 @@ class mstr_layergen:
details_pix[shf_x, shf_y] = (187-d, 179-d, 176-d, aa) details_pix[shf_x, shf_y] = (187-d, 179-d, 176-d, aa)
details_pix[shf_x2, shf_y2] = (187-d2, 179-d2, 176-d2, aa) details_pix[shf_x2, shf_y2] = (187-d2, 179-d2, 176-d2, aa)
# Image for roof details
roof_details = Image.new("RGBA", (self._imgsize, self._imgsize))
roof_det_pix = roof_details.load()
for y in range(self._imgsize):
for x in range(self._imgsize):
mp = mask_pix[x,y]
if mp[3] == 255:
# Determine if we render some pixel
rnd = randrange(1, 3)
if rnd == 2:
# Find a range for the base color of the pixel
d = randrange(21)
# Find a random alpha value
a = randrange(1, 151)
nc = (mstr_building_detail_colors[0][0]-d, mstr_building_detail_colors[0][1]-d, mstr_building_detail_colors[0][2]-d, a)
roof_det_pix[x,y] = nc
layer_comp.alpha_composite(roof_details)
# Let's see how it works with this method # Let's see how it works with this method
details.save(mstr_datafolder + "_cache/" + str(self._latitude) + "-" + str(self._lat_number) + "_" + str(self._longitude) + "-" + str(self._lng_number) + "_" + self._tag + "-" + self._value + "_layer_details.png") details.save(mstr_datafolder + "_cache/" + str(self._latitude) + "-" + str(self._lat_number) + "_" + str(self._longitude) + "-" + str(self._lng_number) + "_" + self._tag + "-" + self._value + "_layer_details.png")
@ -899,7 +894,8 @@ class mstr_layergen:
for x in range(self._imgsize): for x in range(self._imgsize):
tp = tree_pix[x,y] tp = tree_pix[x,y]
if tp[3] > 0: if tp[3] > 0:
sc = (0,0,0,180) rndshd = randrange(5, 210)
sc = (0,0,0,rndshd)
if x+8 < self._imgsize and y+5 < self._imgsize: if x+8 < self._imgsize and y+5 < self._imgsize:
shadow_pix[x+8,y+5] = sc shadow_pix[x+8,y+5] = sc
tree_shadow = tree_shadow.filter(ImageFilter.GaussianBlur(radius=2)) tree_shadow = tree_shadow.filter(ImageFilter.GaussianBlur(radius=2))
@ -959,6 +955,61 @@ class mstr_layergen:
layer_comp_pix[x,y] = (nr, ng, nb, c[3]) layer_comp_pix[x,y] = (nr, ng, nb, c[3])
#layer_comp = layer_comp.filter(ImageFilter.GaussianBlur(radius=1)) #layer_comp = layer_comp.filter(ImageFilter.GaussianBlur(radius=1))
# Let's add some details to the roofs
if self._tag == "building":
vls = [ "detached", "hotel", "farm", "semidetached_house", "apartments", "civic", "house", "school", "kindergarten", "yes" ]
if self._value in vls:
roof_additional_detail = Image.new("RGBA", (self._imgsize, self._imgsize))
rad_pix = roof_additional_detail.load()
for r in range(30001):
lx = randrange(self._imgsize)
ly = randrange(self._imgsize)
mp = mask_pix[lx,ly]
if mp[3] == 255:
# Brighter or darker pixel
bod = randrange(1,3)
c = 0
if bod == 2:
c = 40
else:
c = 200
dt = (c, c, c, 130)
rad_pix[lx,ly] = dt
if lx+1 < self._imgsize:
rad_pix[lx+1, ly] = dt
if lx+1 < self._imgsize and ly+1 < self._imgsize:
rad_pix[lx+1, ly+1] = dt
if ly+1 < self._imgsize:
rad_pix[lx, ly+1] = dt
layer_comp.alpha_composite(roof_additional_detail)
# Let's put some other details on commercial buildings
if self._tag == "building":
vls = [ "office", "retail", "industrial" ]
if self._value in vls:
# Find a suitable location to render something
for r in range(15001):
lx = randrange(self._imgsize)
ly = randrange(self._imgsize)
mp = mask_pix[lx,ly]
# Think of some random shape
if mp[3] == 255:
rw = randrange(3,8)
rh = randrange(3,8)
sh = Image.new("RGBA", (rw, rh), (30,30,30,130))
shp = sh.load()
for sy in range(rh):
for sx in range(rw):
if sx > 0 and sx < rw and sy > 0 and sy < rh: shp[sx, sy] = (180,180,180,160)
rt = randrange(1, 3)
if rt == 2:
sh = sh.rotate(45, expand=True)
layer_comp.alpha_composite(sh, (lx, ly))
# Highways and runways of any kind get some special treatment # Highways and runways of any kind get some special treatment
if (self._tag == "highway" and self._value == "motorway") or (self._tag == "highway" and self._value == "primary") or (self._tag == "highway" and self._value == "secondary") or (self._tag == "highway" and self._value == "tertiary") or (self._tag == "aeroway" and self._value == "runway"): if (self._tag == "highway" and self._value == "motorway") or (self._tag == "highway" and self._value == "primary") or (self._tag == "highway" and self._value == "secondary") or (self._tag == "highway" and self._value == "tertiary") or (self._tag == "aeroway" and self._value == "runway"):
@ -1072,6 +1123,7 @@ class mstr_layergen:
ptc_src.append(Image.open(p)) ptc_src.append(Image.open(p))
osm_mask = Image.open( mstr_datafolder + "_cache/" + str(self._latitude) + "-" + str(self._lat_number) + "_" + str(self._longitude) + "-" + str(self._lng_number) + "_" + self._tag + "-" + self._value + ".png" ) osm_mask = Image.open( mstr_datafolder + "_cache/" + str(self._latitude) + "-" + str(self._lat_number) + "_" + str(self._longitude) + "-" + str(self._lng_number) + "_" + self._tag + "-" + self._value + ".png" )
lyr_mask = Image.open( mstr_datafolder + "_cache/" + str(self._latitude) + "-" + str(self._lat_number) + "_" + str(self._longitude) + "-" + str(self._lng_number) + "_" + self._tag + "-" + self._value + "_layer.png" )
for i in mstr_mask_blur: for i in mstr_mask_blur:
if i[0] == self._tag and i[1] == self._value: if i[0] == self._tag and i[1] == self._value:
@ -1095,11 +1147,12 @@ class mstr_layergen:
adj_image.alpha_composite( brd_src ) adj_image.alpha_composite( brd_src )
lyr_pix = lyr_mask.load()
for y in range(self._imgsize): for y in range(self._imgsize):
for x in range(self._imgsize): for x in range(self._imgsize):
if mask_pix[x, y][3] > 0: if lyr_pix[x, y][3] > 0:
rgb=adj_pix[x,y] rgb=adj_pix[x,y]
a=mask_pix[x,y] a=lyr_pix[x,y]
adj_pix[x, y] = ( rgb[0], rgb[1], rgb[2], a[3]) adj_pix[x, y] = ( rgb[0], rgb[1], rgb[2], a[3])
# Up until here we mimiced the exact same behavior as layergen. However, now # Up until here we mimiced the exact same behavior as layergen. However, now

View File

@ -71,7 +71,7 @@ class mstr_photogen:
if l[0] == "building": if l[0] == "building":
if os.path.isfile(root_filename + l[0] + "-" + l[1] + "_layer.png"): if os.path.isfile(root_filename + l[0] + "-" + l[1] + "_layer.png"):
bld = Image.open(root_filename + l[0] + "-" + l[1] + "_layer.png") bld = Image.open(root_filename + l[0] + "-" + l[1] + "_layer.png")
bld = bld.filter(ImageFilter.GaussianBlur(radius=1)) bld = bld.filter(ImageFilter.GaussianBlur(radius=0.7))
bldg_main.alpha_composite(bld) bldg_main.alpha_composite(bld)
# Trees merging # Trees merging
tree_main = Image.new("RGBA", (self._imgsize, self._imgsize)) tree_main = Image.new("RGBA", (self._imgsize, self._imgsize))

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB