Script output
Grayscale rivermask
My main problem is my script is still making parts of the river more than 1px wide, particularly junctions and what i guess would be curves of 1px radius. Here is the script:
from PIL import Image
import numpy as np
from skimage import morphology
from scipy.ndimage import label
# File paths (update these to match your files)
RIVER_MASK_PATH = "river_mask.png" # e.g., "river_mask.png"
OUTPUT_PATH = "river_map_output.png" # e.g., "river_map_output.png"
# Load river mask as grayscale
river_img = Image.open(RIVER_MASK_PATH).convert("I") # 16-bit grayscale (0-65535)
river_array = np.array(river_img, dtype=np.uint16)
# For 8-bit grayscale, use this instead:
# river_img = Image.open(RIVER_MASK_PATH).convert("L") # 8-bit grayscale (0-255)
# river_array = np.array(river_img, dtype=np.uint8)
# Threshold to create a binary mask (river = True, background = False)
river_binary = river_array > 0
# Skeletonize to make rivers 1px wide
river_skeleton = morphology.skeletonize(river_binary)
# Function to convert to 4-directional connectivity
def convert_to_4connected(skeleton):
height, width = skeleton.shape
river_4dir = skeleton.copy()
for y in range(height - 1):
for x in range(width - 1):
if skeleton[y, x]:
# Check for diagonal connections
if skeleton[y + 1, x + 1] and not (skeleton[y + 1, x] or skeleton[y, x + 1]):
# Break diagonal by adding an intermediate pixel
river_4dir[y + 1, x] = True # Add vertical connection
if skeleton[y + 1, x - 1] and not (skeleton[y + 1, x] or skeleton[y, x - 1]):
river_4dir[y + 1, x] = True
return river_4dir
# Apply 4-directional connectivity
river_4dir = convert_to_4connected(river_skeleton)
# Remove small isolated rivers (≤5 pixels)
labeled_rivers, _ = label(river_4dir)
river_sizes = np.bincount(labeled_rivers.ravel())
small_rivers = np.where((river_sizes <= 5) & (river_sizes > 0))[0]
for label_id in small_rivers:
river_4dir[labeled_rivers == label_id] = False
# Define CK3 river colors and width thresholds
def get_river_color(value, max_value=255):
if max_value == 255: # 8-bit
if value <= 85:
return (0, 255, 255) # Narrow: Cyan
elif value <= 170:
return (0, 128, 255) # Medium: Medium blue
else:
return (0, 0, 255) # Wide: Pure blue
else: # 16-bit
if value <= 10542:
return (0, 255, 255)
elif value <= 41720:
return (0, 128, 255)
else:
return (0, 0, 255)
# Create a 3-channel color image
height, width = river_4dir.shape
river_map_color = np.zeros((height, width, 3), dtype=np.uint8)
# Assign colors to river pixels
max_value = 255 if river_array.dtype == np.uint8 else 65535
for y in range(height):
for x in range(width):
if river_4dir[y, x]:
value = river_array[y, x]
river_map_color[y, x] = get_river_color(value, max_value)
# Save the output as an RGB image
output_img = Image.fromarray(river_map_color, mode="RGB")
output_img.save(OUTPUT_PATH)
print(f"River map saved to {OUTPUT_PATH}")
Here is the link to the wiki page talking about rivermaps:
I've been stuck trying to fix this for a week now using all the ais (chatgpt, deepseek and grok) but can't really fix this issue.
Edit: I'm sorry if the question is not clear, let me clarify, essentially I need the resulting image to abide by ck3 rivermap rules. Specifically the perfect pixel rule. If you check the resulting image you'll see that there are parts of the rivers that are more than 2 pixels wide, particularly junctions. In the wiki there is an image example of how a rivermap should look (Ireland and part of Great Britain). I'm not a programmer by any means and it's my first time posting here so yeah my bad for not explaining the question better.
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744222801a4563864.html
评论列表(0条)