HRSC2016数据集处理避坑指南:从XML旋转框到YOLO格式的完整转换流程

张开发
2026/4/13 11:19:54 15 分钟阅读

分享文章

HRSC2016数据集处理避坑指南:从XML旋转框到YOLO格式的完整转换流程
HRSC2016数据集实战旋转框转换与YOLO格式处理的深度解析第一次接触HRSC2016数据集时我被那些复杂的旋转框标注弄得晕头转向。作为专门用于船舶检测的数据集HRSC2016的XML标注格式与常规水平框完全不同而将其转换为YOLO可用的格式更是一路踩坑。本文将分享我从原始XML到最终YOLO格式的完整转换经验特别聚焦那些容易出错的细节和验证方法。1. 理解HRSC2016数据集结构HRSC2016数据集包含两个主要文件夹Train和Test。每个文件夹下都有两个关键子目录AllImages存储.bmp格式的原始图像Annotations包含XML格式的标注文件XML标注的核心信息集中在HRSC_Object节点中特别是以下几个关键字段HRSC_Object Class_ID17001/Class_ID mbox_cx569.5045/mbox_cx mbox_cy263.4875/mbox_cy mbox_w261.0578/mbox_w mbox_h65.08137/mbox_h mbox_ang-1.562451/mbox_ang /HRSC_Object这些字段定义了旋转框的中心点坐标(cx,cy)、宽度(w)、高度(h)和旋转角度(ang)。需要注意的是角度以弧度表示正值表示顺时针旋转宽度和高度是旋转前的原始尺寸Class_ID的前两位通常表示大类后三位表示具体子类2. 从XML到DOTA格式旋转框顶点计算转换的第一步是将中心点表示法转换为四个顶点坐标。这是通过hrsc2dota.py脚本完成的核心在于旋转矩阵的应用def get_rotated_box_vertices(labels, label_path): with open(label_path,w) as f: for i in range(len(labels)): class_id, mbox_cx, mbox_cy, mbox_w, mbox_h, angle_rad labels[i] # 构建旋转矩阵 rotation_matrix np.array([ [np.cos(angle_rad), -np.sin(angle_rad)], [np.sin(angle_rad), np.cos(angle_rad)] ]) # 计算半宽高 box_half_width mbox_w / 2 box_half_height mbox_h / 2 # 定义原始顶点(未旋转) box_vertices np.array([ [-box_half_width, -box_half_height], [box_half_width, -box_half_height], [box_half_width, box_half_height], [-box_half_width, box_half_height] ]) # 应用旋转 rotated_vertices np.dot(box_vertices, rotation_matrix.T) # 平移至中心点 rotated_vertices[:, 0] mbox_cx rotated_vertices[:, 1] mbox_cy # 四舍五入为整数 rotated_vertices np.round(rotated_vertices).astype(np.int32) rotated_vertices rotated_vertices.reshape(-1) # 写入文件x1 y1 x2 y2 x3 y3 x4 y4 class_id f.write( .join([str(a) for a in rotated_vertices]) str(class_id) \n)注意实际应用中建议先创建DOTA_labels目录再运行脚本否则会报错。对于Train和Test集需要分别处理。3. 可视化验证确保转换正确性转换后必须验证结果dota_drawed.py脚本可以将旋转框绘制到图像上img cv2.imread(img_path) poly [] for i in range(len(objects)): poly.append(np.array(objects[i][poly], dtypenp.int32)) cv2.polylines(img, poly, isClosedTrue, color(255, 0, 0), thickness2) cv2.imwrite(drawed_img_path, img)常见问题及排查方法框体错位检查旋转矩阵计算是否正确特别是角度符号框体变形确认宽度和高度是否对应正确的边类别错误验证Class_ID的解析逻辑4. DOTA到YOLO格式的转换策略dota2yolo.py脚本完成了关键的类型映射和归一化处理。这里有几个技术要点4.1 类别映射简化原始HRSC2016有31个细粒度类别但实际应用中常合并为4个大类aircraft_carrier [2,5,6,12,13,31,32,33] # 航空母舰 warcraft [3,7,8,9,10,11,14,15,16,17,19,28,29] # 军舰 merchant_ship [4,18,20,22,24,25,26,30] # 商船 submarine [27] # 潜艇4.2 归一化处理YOLO格式要求坐标归一化到[0,1]范围x1_normalized x1 / image_width y1_normalized y1 / image_height # 其他坐标点同理...4.3 关于14的谜团原始代码中有个令人困惑的操作# 原作者注释掉的代码 # aircraft_carrier [x 14 for x in aircraft_carrier]经过分析这是早期版本中类别ID偏移导致的。在最新HRSC2016数据集中Class_ID直接从XML读取即可取模运算class_id int(obj.find(Class_ID).text) % 100已足够不需要额外14的偏移量5. 数据集划分与YOLO适配使用split.py脚本划分训练集和验证集时需要注意路径设置必须与实际目录结构一致建议比例训练集80%验证集20%最终YOLO数据集目录结构应如下mydataset/ ├── images/ │ ├── train/ │ └── val/ └── labels/ ├── train/ └── val/每个标签文件内容格式示例1 0.512345 0.423456 0.534567 0.412345 0.545678 0.456789 0.523456 0.4678906. 高级技巧与性能优化在实际项目中我还发现几个提升效率的方法批量处理加速使用多进程处理大量图像from multiprocessing import Pool def process_single(args): xml_path, txt_path args get_rotated_box_vertices(get_label(xml_path), txt_path) if __name__ __main__: args_list [(os.path.join(xml_root,name), os.path.join(txt_root,name.split(.)[0].txt)) for name in os.listdir(xml_root)] with Pool(4) as p: # 4个进程 p.map(process_single, args_list)验证脚本增强添加随机颜色和透明度color (random.randint(0,255), random.randint(0,255), random.randint(0,255)) overlay img.copy() cv2.fillPoly(overlay, [poly], color) img cv2.addWeighted(overlay, 0.3, img, 0.7, 0)异常处理对无效标注的容错机制try: angle_rad float(obj.find(mbox_ang).text) if not -math.pi angle_rad math.pi: angle_rad angle_rad % (2*math.pi) if angle_rad math.pi: angle_rad - 2*math.pi except: print(fInvalid angle in {xml_path}, using 0) angle_rad 0.0处理HRSC2016数据集最耗时的部分不是代码运行而是反复验证每个转换环节的正确性。我建议在关键步骤都添加可视化验证虽然这会增加一些开发时间但能避免后续训练时的各种诡异问题。

更多文章