OpenCV图像与标签旋转问题:仅图像旋转,标签未同步旋转
同步旋转图像与XML标签的实现方案
要解决图像旋转后标签未同步的问题,核心是对XML文件中的**目标边界框(Bounding Box)**进行对应角度的坐标变换,同时更新图像尺寸信息。以下是修改后的完整代码:
import cv2 import os import xml.etree.ElementTree as ET def rotate_bbox(bbox, original_size, rotated_angle): """根据旋转角度计算变换后的边界框坐标""" xmin, ymin, xmax, ymax = bbox original_w, original_h = original_size if rotated_angle == 90: # 顺时针旋转90度 new_w, new_h = original_h, original_w # 坐标转换:原(x,y) → 新(y, original_w - x) new_xmin = ymin new_ymin = original_w - xmax new_xmax = ymax new_ymax = original_w - xmin elif rotated_angle == 180: # 旋转180度 new_w, new_h = original_w, original_h # 坐标转换:原(x,y) → 新(original_w - x, original_h - y) new_xmin = original_w - xmax new_ymin = original_h - ymax new_xmax = original_w - xmin new_ymax = original_h - ymin elif rotated_angle == -90: # 逆时针旋转90度(等价于顺时针270度) new_w, new_h = original_h, original_w # 坐标转换:原(x,y) → 新(original_h - y, x) new_xmin = original_h - ymax new_ymin = xmin new_xmax = original_h - ymin new_ymax = xmax else: new_w, new_h = original_w, original_h new_xmin, new_ymin, new_xmax, new_ymax = xmin, ymin, xmax, ymax return (int(new_xmin), int(new_ymin), int(new_xmax), int(new_ymax)), (new_w, new_h) data_directory = "face_dataset" # 仅筛选图像文件 image_files = [file for file in os.listdir(data_directory) if file.lower().endswith((".jpg", ".jpeg", ".png"))] for i, file in enumerate(image_files): image_path = os.path.join(data_directory, file) label_path = os.path.join(data_directory, os.path.splitext(file)[0] + ".xml") # 加载图像 image = cv2.imread(image_path) if image is None: print(f"加载图像失败: {image_path}") continue original_h, original_w = image.shape[:2] # 确定旋转角度与对应OpenCV常量 if i < 55: rotated_angle = 90 cv2_rotate_flag = cv2.ROTATE_90_CLOCKWISE elif i < 110: rotated_angle = 180 cv2_rotate_flag = cv2.ROTATE_180 else: rotated_angle = -90 cv2_rotate_flag = cv2.ROTATE_90_COUNTERCLOCKWISE # 旋转图像并保存 rotated_image = cv2.rotate(image, cv2_rotate_flag) if rotated_image is None: print(f"旋转图像失败: {image_path}") continue cv2.imwrite(image_path, rotated_image) # 处理XML标签(如果存在) if not os.path.exists(label_path): print(f"标签文件不存在: {label_path}") continue # 解析XML并更新内容 tree = ET.parse(label_path) root = tree.getroot() # 更新图像尺寸 size_node = root.find('size') size_node.find('width').text = str(rotated_image.shape[1]) size_node.find('height').text = str(rotated_image.shape[0]) # 更新每个目标的边界框 for obj in root.findall('object'): bndbox = obj.find('bndbox') xmin = int(bndbox.find('xmin').text) ymin = int(bndbox.find('ymin').text) xmax = int(bndbox.find('xmax').text) ymax = int(bndbox.find('ymax').text) new_bbox, _ = rotate_bbox((xmin, ymin, xmax, ymax), (original_w, original_h), rotated_angle) new_xmin, new_ymin, new_xmax, new_ymax = new_bbox bndbox.find('xmin').text = str(new_xmin) bndbox.find('ymin').text = str(new_ymin) bndbox.find('xmax').text = str(new_xmax) bndbox.find('ymax').text = str(new_ymax) # 保存修改后的XML tree.write(label_path)
关键说明
- 坐标变换逻辑:针对三种旋转角度推导了边界框坐标的转换公式,确保旋转后目标位置与图像完全匹配。
- XML处理:通过
ElementTree解析XML结构,更新图像尺寸字段,并遍历所有目标节点修改边界框坐标。 - 代码优化:使用OpenCV官方旋转常量替代数值,提升可读性;增加标签文件存在性检查,避免无意义报错。
内容的提问来源于stack exchange,提问作者Cihan Yalçın
相关产品推荐
相关产品推荐

