You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

图像裁剪缩放后Yolov8格式多边形坐标转换及过滤求助

问题描述

我正在用Python处理图像,流程如下:

  • 在尺寸为1600×1000的原始图像中定位边界框;
  • 将该边界框区域扩大20%;
  • 裁剪出扩大后的区域生成新图像;
  • 将新图像调整至640×640尺寸。

当前遇到的问题:
我持有对应原始图像的多边形坐标列表,格式为[x1, y1, x2, y2, ..., xn, yn],属于Yolov8格式的归一化坐标(取值范围0-1),且坐标可能超出原边界框范围。

需要将这些坐标转换以适配新生成的图像,同时移除不属于新图像的越界多边形。我尝试了以下代码,但计算存在错误,也缺少中心对齐处理:

def transform_coordinates(coordinates, original_image_size, new_image_size, crop_factor=1.2):

    original_width, original_height = original_image_size
    new_width, new_height = new_image_size
    
    coordinates = convert_to_absolute_coordinates(coordinates, original_image_size)

    # Calculate the scaling factors for the transformation
    scale_x = original_width/new_width
    scale_y = original_height/new_height

    # Transform each pair of coordinates in the list
    transformed_coordinates = []
    for i in range(0, len(coordinates), 2):

        x = coordinates[i] * scale_x*crop_factor
        y = coordinates[i + 1] * scale_y*crop_factor

        transformed_coordinates.extend([x, y])

    transformed_coordinates = normalize_coordinates(transformed_coordinates, original_image_size)

    return transformed_coordinates
解决方案

核心转换逻辑

要完成坐标转换,必须先明确原始边界框的位置,再通过中心对齐计算扩大后的裁剪区域,最后逐步将原始坐标映射到新图像:

  1. 将归一化的多边形坐标转为原始图像的绝对坐标;
  2. 基于原始边界框的中心,按比例扩大得到裁剪区域(确保中心对齐);
  3. 将原始多边形坐标转换到裁剪区域的局部坐标系(减去裁剪区域左上角坐标);
  4. 计算裁剪区域到640×640图像的缩放比例,对坐标进行缩放;
  5. 过滤掉完全超出新图像范围的多边形。

修正后的代码

def convert_to_absolute_coordinates(normalized_coords, original_size):
    """将Yolov8归一化坐标转为原始图像绝对坐标"""
    orig_w, orig_h = original_size
    abs_coords = []
    for i in range(0, len(normalized_coords), 2):
        x = normalized_coords[i] * orig_w
        y = normalized_coords[i+1] * orig_h
        abs_coords.extend([x, y])
    return abs_coords

def normalize_coordinates(absolute_coords, target_size):
    """将绝对坐标转为目标尺寸的归一化坐标"""
    target_w, target_h = target_size
    norm_coords = []
    for i in range(0, len(absolute_coords), 2):
        x = absolute_coords[i] / target_w
        y = absolute_coords[i+1] / target_h
        norm_coords.extend([x, y])
    return norm_coords

def transform_polygon_coords(polygon_norm, original_bbox_abs, original_size=(1600, 1000), target_size=(640, 640), crop_factor=1.2):
    """
    转换多边形坐标到新图像,并判断是否越界
    :param polygon_norm: 原始归一化多边形坐标列表 [x1,y1,x2,y2,...]
    :param original_bbox_abs: 原始边界框的绝对坐标 (x_min, y_min, x_max, y_max)
    :param original_size: 原始图像尺寸 (宽, 高)
    :param target_size: 新图像尺寸 (宽, 高)
    :param crop_factor: 边界框扩大比例
    :return: 转换后的归一化坐标,或None(多边形完全越界)
    """
    orig_w, orig_h = original_size
    target_w, target_h = target_size
    
    # 1. 转换为原始图像的绝对坐标
    polygon_abs = convert_to_absolute_coordinates(polygon_norm, original_size)
    
    # 2. 计算中心对齐的扩大裁剪区域
    bbox_x_min, bbox_y_min, bbox_x_max, bbox_y_max = original_bbox_abs
    bbox_w = bbox_x_max - bbox_x_min
    bbox_h = bbox_y_max - bbox_y_min
    
    # 计算边界框中心
    center_x = (bbox_x_min + bbox_x_max) / 2
    center_y = (bbox_y_min + bbox_y_max) / 2
    
    # 扩大后的宽高
    expanded_w = bbox_w * crop_factor
    expanded_h = bbox_h * crop_factor
    
    # 计算裁剪区域的上下左右边界(限制在原始图像内,避免越界)
    crop_x_min = max(0, center_x - expanded_w / 2)
    crop_y_min = max(0, center_y - expanded_h / 2)
    crop_x_max = min(orig_w, center_x + expanded_w / 2)
    crop_y_max = min(orig_h, center_y + expanded_h / 2)
    crop_w = crop_x_max - crop_x_min
    crop_h = crop_y_max - crop_y_min
    
    # 3. 转换到裁剪区域的局部坐标系
    local_coords = []
    has_valid_point = False
    for i in range(0, len(polygon_abs), 2):
        x = polygon_abs[i] - crop_x_min
        y = polygon_abs[i+1] - crop_y_min
        # 检查当前点是否在裁剪区域内(允许微小误差)
        if 0 - 1e-6 <= x <= crop_w + 1e-6 and 0 - 1e-6 <= y <= crop_h + 1e-6:
            has_valid_point = True
        local_coords.extend([x, y])
    
    # 如果所有点都不在裁剪区域内,返回None表示丢弃该多边形
    if not has_valid_point:
        return None
    
    # 4. 缩放到目标图像尺寸
    scale_x = target_w / crop_w
    scale_y = target_h / crop_h
    scaled_coords = []
    for i in range(0, len(local_coords), 2):
        x = local_coords[i] * scale_x
        y = local_coords[i+1] * scale_y
        # 限制坐标在目标图像范围内,避免归一化后超出0-1
        x = max(0, min(x, target_w))
        y = max(0, min(y, target_h))
        scaled_coords.extend([x, y])
    
    # 5. 转换为目标图像的归一化坐标(可选,按需返回绝对坐标或归一化坐标)
    transformed_norm = normalize_coordinates(scaled_coords, target_size)
    
    return transformed_norm

使用说明

  1. 调用时必须传入原始边界框的绝对坐标(比如从检测结果中获取的x_min, y_min, x_max, y_max);
  2. 函数会自动判断多边形是否完全超出裁剪区域,完全越界则返回None,直接丢弃即可;
  3. 若需要保留绝对坐标,直接返回scaled_coords即可,无需最后一步归一化。

内容的提问来源于stack exchange,提问作者anxiousPI

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 12:54:54