Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #! env python3
- #
- # Simple utilite for merging map tiles sessions generated by hafen clients
- # 'maps' or 'map' contains source sessions. Result will be placed to 'tiles'
- from __future__ import print_function
- import os
- import sys
- import re
- import shutil
- from PIL import Image
- import hashlib
- script_root = os.path.dirname(os.path.abspath(__file__))
- if os.path.exists(os.path.join(script_root, 'map')):
- raw_tiles_root = os.path.join(script_root, 'map')
- else:
- raw_tiles_root = os.path.join(script_root, 'maps')
- tiles_root = os.path.join(script_root, 'tiles') # result directory
- processed_tiles_root = os.path.join(script_root, 'processed') # processed sessions
- broken_tiles_root = os.path.join(script_root, 'broken') # sessions which can not be prosessed due tile numbers conflict
- # index file format: lines like 'hash x y'
- index_path = os.path.join(script_root, 'hafen_tiles.index')
- def load_index():
- index = {}
- if os.path.exists(index_path):
- index = {}
- with open(index_path, 'r') as f:
- for line in f:
- h, x, y = line.split()
- index[h] = (int(x), int(y))
- return index
- def save_index(index):
- if os.path.exists(index_path):
- shutil.copy(index_path, index_path + '.bak')
- with open(index_path, 'w') as f:
- for h in index:
- x, y = index[h]
- f.write('%s %s %s\n' % (h, x, y))
- def rebuild_index(index = {}):
- for root, dirs, files in os.walk(tiles_root):
- for f in files:
- filename, file_extension = os.path.splitext(f)
- if file_extension != '.png':
- continue
- img = Image.open(os.path.join(root, f))
- h = calc_image_hash(img)
- if not h:
- continue
- index[h] = tile_offset(filename)
- return index
- def tile_offset(filename):
- x, y = re.search(u'.*_([-0-9]+)_([-0-9]+).*', filename).groups()
- return (int(x), int(y))
- def calc_image_hash(img):
- '''
- Calc hash based on biom borders shape
- '''
- width, height = img.size
- m = hashlib.md5()
- offset = None # some clients generate tiles with offset
- black_count = 0 # we can not buld hash for tiles without borders
- for x in range(5, width - 5):
- for y in range(5, height - 5):
- pixel = img.getpixel((x,y))
- if pixel[0] == 0 and pixel[1] == 0 and pixel[2] == 0:
- black_count += 1
- if not offset:
- offset = (x, y)
- ox, oy = offset
- m.update(str(x - ox).encode('utf-8'))
- m.update(str(y - oy).encode('utf-8'))
- return m.hexdigest() if black_count > 0 else None
- def most_common(lst):
- return max(set(lst), key=lst.count)
- def is_cave(img, weight=100):
- '''
- Detect cave tiles by counting pixels which is not gray
- '''
- width, height = img.size
- color_count = 0
- for x in range(5, width - 5):
- for y in range(5, height - 5):
- pixel = img.getpixel((x,y))
- avg = (pixel[0] + pixel[1] + pixel[2]) / 3.0
- if pixel[0] == 0 and pixel[1] == 0 and pixel[2] == 0:
- continue
- if abs(pixel[0] / avg - 1) > 0.2 or \
- abs(pixel[1] / avg - 1) > 0.2 or \
- abs(pixel[2] / avg - 1) > 0.2:
- color_count += 1
- return color_count < weight
- print('Reading index...')
- index = load_index()
- print(len(index), ' items')
- # trying rebuild index if it is empty
- if len(index) < 50:
- print('Rebuilding index...')
- index = rebuild_index(index=index)
- print(len(index), ' items')
- print('New tiles analysing...')
- founded_tiles = 0
- cache = {}
- cave_cache = {}
- iteration_founded = None
- while iteration_founded is None or iteration_founded > 0:
- founded_tiles += iteration_founded if iteration_founded else 0
- iteration_founded = 0
- offsets = {}
- broken_sessions = []
- session_hashes = {}
- # Scaning sessions
- for root, dirs, files in os.walk(raw_tiles_root):
- for f in files:
- filename, file_extension = os.path.splitext(f)
- if file_extension != '.png':
- continue
- full_path = os.path.join(root, f)
- h = cache[full_path] if full_path in cache else calc_image_hash(Image.open(full_path))
- cache[full_path] = h
- if not h:
- continue
- in_cave = cave_cache[full_path] if full_path in cave_cache else is_cave(Image.open(full_path))
- cave_cache[full_path] = in_cave
- if in_cave:
- continue
- if not root in session_hashes:
- session_hashes[root] = {}
- # detect equal tiles with different names into one session
- if h in session_hashes[root]:
- broken_sessions += [root]
- continue
- session_hashes[root][h] = filename
- if h in index.keys():
- print('%s %s match' % (full_path, h))
- x, y = tile_offset(filename)
- ix, iy = index[h]
- if not root in offsets:
- offsets[root] = []
- offsets[root] += [(ix - x, iy - y)]
- # Selecting session offset related (0, 0)
- founded = {}
- for d in offsets.keys():
- var = most_common(offsets[d])
- if offsets[d].count(var) >= 3 or len(index) < 150:
- founded[d] = var
- else:
- print('"%s" contains not enought matched tiles (%s). Ignored' % (d, offsets[d].count(var)))
- if not os.path.exists(tiles_root):
- os.makedirs(tiles_root)
- # Copy session tiles to result direcory
- for root, dirs, files in os.walk(raw_tiles_root):
- for f in files:
- # if session offset is not found
- if not root in founded:
- continue
- if root in broken_sessions:
- if not os.path.exists(broken_tiles_root):
- os.makedirs(broken_tiles_root)
- if os.path.exists(root):
- print('"%s" has tile names conflict. Moved to ""' % (root, broken_tiles_root))
- shutil.move(root, broken_tiles_root)
- continue
- filename, file_extension = os.path.splitext(f)
- if file_extension != '.png':
- continue
- x, y = tile_offset(filename)
- ix, iy = founded[root]
- full_path = os.path.join(root, f)
- h = cache[full_path] if full_path in cache else calc_image_hash(Image.open(full_path))
- cache[full_path] = h
- in_cave = cave_cache[full_path] if full_path in cave_cache else is_cave(Image.open(full_path))
- cave_cache[full_path] = in_cave
- if in_cave:
- continue
- if h:
- if h in index and index[h] != (x + ix, y + iy):
- print('Warning! %s (%s, %s) (%s) may has wrong name. Already indexed as (%s, %s)' % \
- (h, x + ix, y + iy, full_name, index[h][0], index[h][1]))
- else:
- index[h] = (x + ix, y + iy)
- new_filename = 'tile_%s_%s.png' % (x + ix, y + iy)
- shutil.copy(os.path.join(root, f), os.path.join(tiles_root, new_filename))
- print('%s -> %s' % (full_path, os.path.join(tiles_root, new_filename)))
- iteration_founded += 1
- if not os.path.exists(processed_tiles_root):
- os.makedirs(processed_tiles_root)
- for d in founded.keys():
- if os.path.exists(d):
- shutil.move(d, processed_tiles_root)
- save_index(index)
- print('%s new tiles in "%s"' % (founded_tiles, tiles_root))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement