[Python] Need help in my script (made with grok) that converts a grayscale river mask of my...

Discussão em 'Python' iniciado por Stack, Março 25, 2025.

  1. Stack

    Stack Membro Participativo

    Script output

    Grayscale rivermask

    What the title says, main problem is it 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: https://ck3.paradoxwikis.com/Map_modding#River_map

    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.

    Continue reading...

Compartilhe esta Página