Skip to content

Request: Create a HIRES composite image with both terrain and water #14

@AaronConrad

Description

@AaronConrad

I've seen several 3D printed maps using the height map. (And I'm going to make one of my own.) Fixing the water level is a tedious task. It would be nice to have a height map with both terrain and water combined.

The script below is my attempt to create a composite image. It just layers all of the water height maps and takes the largest pixel value. Then it adds the HIRES terrain map using the same process.

There are four disadvantages to my script:

  1. The water maps are at a much lower resolution, so have to be significantly scaled.
  2. The water maps are 8-bit instead of 16-bit, so the heights also have to be scaled.
  3. The water maps encompass a smaller area than the HIRES terrain map. I've got a decent attempt on how to align them, but I'm not sure it's perfect.
  4. I don't have a platform to distribute the final composite to people who want it.

For these reasons, I believe adding an official combined composite image would be good. I personally don't need anything bigger than 8K by 8K.

import cv2
import numpy as np
import glob

water_map_format = 'heightmap_water*.png'
terrain_map_file = 'heightmap_HIRES_0.125_resized.png'

water_composite_output = 'water_composite.png'
complete_composite_output = 'complete_composite.png'

# Load the water maps
png_files = sorted(glob.glob(water_map_format))

# Read the first map to start the composite
water_composite = cv2.imread(png_files[0], cv2.IMREAD_GRAYSCALE)

# Compare with remaining images
for file in png_files[1:]:
    img = cv2.imread(file, cv2.IMREAD_GRAYSCALE)  # 8-bit grayscale
    # Take the highest pixel value
    water_composite = np.maximum(water_composite, img)

# Load the terrain image to get its dimensions
terrain_image = cv2.imread(terrain_map_file, cv2.IMREAD_UNCHANGED)  # 16-bit grayscale
terrain_height, terrian_width = terrain_image.shape

# Resize the water composite image to match the terrain

# TODO: This is an estimation.
# Assume the water map is 2/3 the size of the terrain map.
# Add a black border to cover the last bit, then resize.
# Also assume this is a square image.
h, w = water_composite.shape
border_size = int(h * 0.33333 / 2)
water_composite = cv2.copyMakeBorder(
    water_composite,
    border_size,
    border_size,
    border_size,
    border_size,
    borderType=cv2.BORDER_CONSTANT,
    value=[0, 0, 0]
)

# Scale it to match the terrain map
water_composite = cv2.resize(water_composite, (terrain_height, terrian_width), interpolation=cv2.INTER_LINEAR)

# Rescale the water composite values to be 16bit
water_composite = water_composite.astype(np.uint16) * 257

# Save off the water composite
cv2.imwrite(water_composite_output, water_composite)

# Combine the terrain and water maps
complete_composite = np.maximum(water_composite, terrain_image)

# Save the result
cv2.imwrite(complete_composite_output, complete_composite)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions