[Python] How to number multiple objects in an image according to my desired order

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

  1. Stack

    Stack Membro Participativo

    enter image description hereI have a picture of a row of five, two rows totaling ten objects, and I want him to number them in order from left to right, top to bottom. Previously I had boxed each object with the smallest outer rectangle, the next step was to number them, but when I numbered them I realized that he couldn't do it in left to right order, instead it was right to left or the order was messed up.

    Here's my code:

    import cv2
    import numpy as np
    import os

    # 输入输出路径
    input_folder = "D:\\beimu\\1" # 已包含绿色框的图像
    output_folder = "D:\\beimu\\1" # 输出带编号图像
    os.makedirs(output_folder, exist_ok=True)

    # 行聚类阈值:允许每行贝母中心 y 坐标最大偏差
    ROW_THRESHOLD = 25

    def group_rows_by_y(items, threshold=ROW_THRESHOLD):
    """按Y坐标分组为“行”"""
    items = sorted(items, key=lambda x: x['center'][2])
    rows = []
    current_row = []
    current_y = None

    for item in items:
    y = item['center'][2]
    if not current_row:
    current_row = [item]
    current_y = y
    elif abs(y - current_y) <= threshold:
    current_row.append(item)
    else:
    rows.append(current_row)
    current_row = [item]
    current_y = y
    if current_row:
    rows.append(current_row)
    return rows

    def number_and_save(image_path, output_path):
    image = cv2.imread(image_path)

    # 提取绿色框区域
    green_mask = cv2.inRange(image, (0, 250, 0), (0, 255, 0))
    contours, _ = cv2.findContours(green_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

    rects = []
    for cnt in contours:
    rect = cv2.minAreaRect(cnt)
    box = cv2.boxPoints(rect)
    box = np.intp(box)
    center = np.mean(box, axis=0)
    top_left = box[np.argmin(box[:, 0] + box[:, 1])] # 找到左上角点
    rects.append({
    'box': box,
    'center': center,
    'top_left': top_left
    })

    # 聚类:先按Y分组为“行”
    grouped_rows = group_rows_by_y(rects)

    # 对每一行按中心点X坐标排序,整体编号
    count = 1
    for row in grouped_rows:
    # 按中心点的X坐标排序,确保从左到右
    row.sort(key=lambda x: x['center'][0])
    for item in row:
    box = item['box']
    top_left = tuple(np.intp(item['top_left']))
    label_pos = (top_left[0] - 10, top_left[2] - 10)
    cv2.drawContours(image, [box], 0, (0, 255, 0), 2)
    cv2.putText(image, str(count), label_pos, cv2.FONT_HERSHEY_SIMPLEX,
    0.8, (0, 0, 255), 2)
    count += 1

    cv2.imwrite(output_path, image)
    print(f"✅ 编号完成:{os.path.basename(image_path)} → {output_path}")

    # 遍历处理整个文件夹
    for filename in os.listdir(input_folder):
    if filename.lower().endswith(('.png', '.jpg', '.jpeg')):
    in_path = os.path.join(input_folder, filename)
    out_path = os.path.join(output_folder, f"numbered_{filename}")
    number_and_save(in_path, out_path)

    print("\n 所有图像编号完成,已保存至:", output_folder)


    The logic of my code is to first find the four points of each rectangular box and find the center coordinates. Look at the left side of the Y first for clustering so that the objects can be divided into two rows. After that sort by center coordinates. I printed the debugging information and found that the center coordinates of the rightmost object are the smallest, which doesn't match the logic I had envisioned for myself. I don't think I understood his logic for solving for each coordinate I modified the row threshold and also modified x: x ['center'] to top left I was hoping to be able to sort in order from left to right to lay the groundwork for further experiments to follow.

    Continue reading...

Compartilhe esta Página