[Python] How to calculate the center-line or baseline of a polygon

Discussão em 'Python' iniciado por Stack, Junho 16, 2025.

  1. Stack

    Stack Membro Participativo

    I work on a segmentation model for historical documents. My dataset has the text lines as polygons but for a usable model training I need also the center-lines or baselines of the polygons.

    As an example, these are the coordinates of the line as tuples of polygons:

    603,1220 600,1288 687,1304 691,1304 694,1304 726,1291 762,1278 801,1291 843,1307 846,1307 850,1307 924,1294 976,1285 1009,1294 1054,1310 1057,1310 1061,1310 1158,1298 1203,1291 1223,1298 1262,1314 1265,1314 1268,1314 1272,1314 1320,1298 1366,1285 1388,1301 1405,1310 1408,1310 1411,1310 1745,1323 1749,1323 1752,1323 1788,1304 1810,1294 1891,1294 1963,1307 2057,1327 2060,1327 2161,1310 2222,1301 2317,1314 2359,1317 2362,1317 2388,1314 2440,1304 2459,1314 2495,1336 2498,1336 2502,1336 2505,1336 2602,1317 2651,1307 2738,1317 2878,1336 2881,1336 2884,1336 2943,1320 2972,1314 3248,1323 3258,1262 3254,1203 603,1151 603,1220


    And this is the baseline of the above coordinates:

    603,1220 2138,1255 3258,1262


    I try to use python's shapely.centroid to calculate the baseline but without reliable result.

    from shapely import LineString, MultiPoint, Polygon, centroid

    print(centroid(Polygon([(584, 1603), (580, 1654), (649, 1680), (652, 1680), (824, 1684), (827, 1684), (830, 1684), (918, 1661), (947, 1684), (950, 1684), (954, 1684), (957, 1684), (1061, 1671), (1106, 1687), (1109, 1687), (1113, 1687), (1116, 1687), (1187, 1664), (1343, 1690), (1346, 1690), (1732, 1671), (1758, 1671), (1797, 1671), (2158, 1693), (2161, 1693), (2164, 1693), (2193, 1677), (2196, 1677), (2239, 1700), (2242, 1700), (2245, 1700), (2248, 1700), (2320, 1680), (2323, 1680), (2404, 1703), (2407, 1703), (2411, 1703), (2667, 1687), (2712, 1684), (2719, 1687), (2771, 1710), (2774, 1710), (2777, 1710), (3261, 1693), (3267, 1638), (3264, 1570), (584, 1538), (584, 1603)])))


    Result:

    POINT (1920.3383138928723 1620.2116469627338)


    Image: [​IMG]

    EDIT: I forgot to mention, if this matters or not, my image has the following measures in this case: imageWidth="4381" imageHeight="5841"

    After some research I came up with this code, though I don't get a central line but the upper line of the polygon:

    import numpy as np
    import matplotlib.pyplot as plt

    # Given polygon points (as x, y coordinates) for the shape
    polygon_points = [
    (603, 1220), (600, 1288), (687, 1304), (691, 1304), (694, 1304),
    (726, 1291), (762, 1278), (801, 1291), (843, 1307), (846, 1307),
    (850, 1307), (924, 1294), (976, 1285), (1009, 1294), (1054, 1310),
    (1057, 1310), (1061, 1310), (1158, 1298), (1203, 1291), (1223, 1298),
    (1262, 1314), (1265, 1314), (1268, 1314), (1272, 1314), (1320, 1298),
    (1366, 1285), (1388, 1301), (1405, 1310), (1408, 1310), (1411, 1310),
    (1745, 1323), (1749, 1323), (1752, 1323), (1788, 1304), (1810, 1294),
    (1891, 1294), (1963, 1307), (2057, 1327), (2060, 1327), (2161, 1310),
    (2222, 1301), (2317, 1314), (2359, 1317), (2362, 1317), (2388, 1314),
    (2440, 1304), (2459, 1314), (2495, 1336), (2498, 1336), (2502, 1336),
    (2505, 1336), (2602, 1317), (2651, 1307), (2738, 1317), (2878, 1336),
    (2881, 1336), (2884, 1336), (2943, 1320), (2972, 1314), (3248, 1323),
    (3258, 1262), (3254, 1203), (603, 1151), (603, 1220)
    ]

    image_width = 4381
    image_height = 5841

    normalized_polygon_points = [(x / image_width, y / image_height) for x, y in polygon_points]

    # Extract x and y coordinates from the polygon points
    x_coords, y_coords = zip(*normalized_polygon_points)

    # Create a dictionary to store top and bottom y-values for each x-coordinate
    x_to_y_values = {}

    for x, y in normalized_polygon_points:
    if x not in x_to_y_values:
    x_to_y_values[x] = {'top': y, 'bottom': y}
    else:
    # Update the top and bottom y-values for the x-coordinate
    if y < x_to_y_values[x]['top']:
    x_to_y_values[x]['top'] = y # Update top
    if y > x_to_y_values[x]['bottom']:
    x_to_y_values[x]['bottom'] = y # Update bottom

    # Calculate the centerline by averaging the top and bottom y-values for each x-coordinate
    centerline_points = []
    for x in sorted(x_to_y_values.keys()):
    top_y = x_to_y_values[x]['top']
    bottom_y = x_to_y_values[x]['bottom']
    center_y = (top_y + bottom_y) / 2 # Midpoint between top and bottom
    centerline_points.append((x, center_y))

    # Extract the centerline x and y points
    centerline_x, centerline_y = zip(*centerline_points)

    # Plot the polygon and the centerline
    plt.figure(figsize=(10, 6))
    plt.plot(x_coords, y_coords, label='Polygon', color='blue', linestyle='--', marker='o')
    plt.plot(centerline_x, centerline_y, label='Centerline', color='red', marker='o')
    plt.title('Polygon with Centerline')
    plt.xlabel('X')
    plt.ylabel('Y')
    plt.legend()
    plt.grid(True)
    plt.show()


    [​IMG]

    Continue reading...

Compartilhe esta Página