图像裁剪缩放后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
解决方案
核心转换逻辑
要完成坐标转换,必须先明确原始边界框的位置,再通过中心对齐计算扩大后的裁剪区域,最后逐步将原始坐标映射到新图像:
- 将归一化的多边形坐标转为原始图像的绝对坐标;
- 基于原始边界框的中心,按比例扩大得到裁剪区域(确保中心对齐);
- 将原始多边形坐标转换到裁剪区域的局部坐标系(减去裁剪区域左上角坐标);
- 计算裁剪区域到640×640图像的缩放比例,对坐标进行缩放;
- 过滤掉完全超出新图像范围的多边形。
修正后的代码
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
使用说明
- 调用时必须传入原始边界框的绝对坐标(比如从检测结果中获取的
x_min, y_min, x_max, y_max); - 函数会自动判断多边形是否完全超出裁剪区域,完全越界则返回
None,直接丢弃即可; - 若需要保留绝对坐标,直接返回
scaled_coords即可,无需最后一步归一化。
内容的提问来源于stack exchange,提问作者anxiousPI
相关产品推荐
相关产品推荐

