admin管理员组文章数量:1400077
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.
本文标签:
版权声明:本文标题:python - Why does my script that converts a grayscale image mask of my map into 1px wide lines make line wider than 1px? - Stack 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744222800a2595948.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论