目标检测项目图像标注全流程及YOLO/COCO适配最佳实践技术问询
大规模目标检测与分割数据集准备最佳实践
一、保持标注一致性
- 制定明确的标注规则手册:针对每个类别定义清晰的标注标准,比如:
- 边界框:必须是目标的最小外接矩形,不能包含无关背景,也不能遗漏目标边缘
- 分割多边形:需精确贴合目标像素级边缘,对于模糊边缘需统一标注规则(如取视觉可见的最外层)
- 统一标注工具:全团队使用同一工具(如CVAT、Labelme),避免不同工具导出格式差异导致的一致性问题
- 建立标注示例库:为每个类别提供5-10张标注规范的样本,作为标注员参考基准
- 批量校验类别一致性:用脚本遍历COCO标注文件,检查所有annotation的
category_id是否在预设的合法ID列表内,防止错标类别import json def check_category_consistency(coco_json_path, valid_category_ids): with open(coco_json_path, 'r') as f: data = json.load(f) invalid_anns = [] for ann in data['annotations']: if ann['category_id'] not in valid_category_ids: invalid_anns.append(ann['id']) if invalid_anns: print(f"发现无效类别标注,标注ID:{invalid_anns}") else: print("类别标注一致性校验通过")
二、验证标注质量
- 自动校验脚本:
- 用
pycocotools验证COCO格式合法性:检查标注文件的结构完整性、图像与标注的对应关系 - 自定义校验逻辑:检查bbox是否超出图像范围、分割多边形是否闭合且面积合理
from pycocotools.coco import COCO import cv2 def validate_annotations(coco_json_path, img_dir): coco = COCO(coco_json_path) for img_id in coco.getImgIds(): img_info = coco.loadImgs(img_id)[0] img_h, img_w = img_info['height'], img_info['width'] ann_ids = coco.getAnnIds(imgIds=img_id) anns = coco.loadAnns(ann_ids) for ann in anns: # 检查bbox范围 x, y, w, h = ann['bbox'] if x < 0 or y < 0 or x + w > img_w or y + h > img_h: print(f"图像{img_info['file_name']}的标注{ann['id']} bbox超出范围") # 检查分割多边形面积(避免过小/无效标注) if 'segmentation' in ann and len(ann['segmentation']) > 0: seg_area = coco.annToArea(ann) if seg_area < 10: # 阈值可调整 print(f"图像{img_info['file_name']}的标注{ann['id']}分割面积过小")
- 用
- 人工交叉审核:随机抽取5%-10%的样本,由至少2名标注员交叉检查,重点审核困难样本(如小目标、模糊目标)
- 标注质量量化:计算标注的IOU一致性(同一样本不同标注员的标注IOU),设定阈值(如≥0.8)判定合格
三、处理类别不平衡
- 数据层面优化:
- 过采样少数类:对少数类样本进行多次增强(如翻转、缩放、亮度调整)后添加到数据集,避免简单复制导致的过拟合
def oversample_minority_class(img_path, ann, augment_times=3): img = cv2.imread(img_path) augmented_imgs = [] augmented_anns = [] for _ in range(augment_times): # 随机水平翻转 flipped_img = cv2.flip(img, 1) # 同步调整bbox和分割标注 h, w = img.shape[:2] flipped_bbox = [w - ann['bbox'][0] - ann['bbox'][2], ann['bbox'][1], ann['bbox'][2], ann['bbox'][3]] flipped_seg = [[w - x, y] for x, y in ann['segmentation'][0]] augmented_imgs.append(flipped_img) augmented_anns.append({'bbox': flipped_bbox, 'segmentation': [flipped_seg], **ann}) return augmented_imgs, augmented_anns - 欠采样多数类:随机删除多数类的冗余样本,或选择具有代表性的样本(如覆盖不同场景、角度的样本)保留
- 合成样本:用CutMix/MixUp方法将少数类样本与其他样本合成新图像,同步生成对应标注
- 过采样少数类:对少数类样本进行多次增强(如翻转、缩放、亮度调整)后添加到数据集,避免简单复制导致的过拟合
- 标注资源倾斜:优先分配更多标注人力到少数类,确保每个少数类样本的标注精度
四、减少预处理阶段标注错误
- 预处理前备份原始数据:对原始图像和标注文件做只读备份,避免预处理失误导致数据丢失
- 标注与图像同步变换:所有图像预处理操作(缩放、翻转、旋转)必须同步调整标注坐标,比如缩放时计算比例因子:
def resize_image_and_annotation(img, ann, target_size=(640, 640)): h, w = img.shape[:2] scale_h = target_size[0] / h scale_w = target_size[1] / w # 缩放图像 resized_img = cv2.resize(img, target_size) # 调整bbox resized_bbox = [ann['bbox'][0] * scale_w, ann['bbox'][1] * scale_h, ann['bbox'][2] * scale_w, ann['bbox'][3] * scale_h] # 调整分割多边形 resized_seg = [[x * scale_w, y * scale_h] for x, y in ann['segmentation'][0]] resized_ann = {'bbox': resized_bbox, 'segmentation': [resized_seg], **ann} return resized_img, resized_ann - 预处理后校验:每次预处理完成后,用脚本检查所有标注的坐标是否在新图像尺寸范围内,避免出现负数或超出边界的情况
五、为YOLO/COCO Pipeline准备数据集
- COCO转YOLO格式:将COCO的json标注转换为YOLO的txt格式,每个图像对应一个txt文件,每行内容为:
类别ID 归一化x_center 归一化y_center 归一化宽度 归一化高度 [归一化分割点x1 y1 x2 y2 ...]def coco_to_yolo(coco_json_path, img_dir, output_dir): import os os.makedirs(output_dir, exist_ok=True) coco = COCO(coco_json_path) for img_id in coco.getImgIds(): img_info = coco.loadImgs(img_id)[0] img_w, img_h = img_info['width'], img_info['height'] ann_ids = coco.getAnnIds(imgIds=img_id) anns = coco.loadAnns(ann_ids) yolo_txt_path = os.path.join(output_dir, os.path.splitext(img_info['file_name'])[0] + '.txt') with open(yolo_txt_path, 'w') as f: for ann in anns: # 处理bbox x, y, w, h = ann['bbox'] x_center = (x + w/2) / img_w y_center = (y + h/2) / img_h norm_w = w / img_w norm_h = h / img_h # 处理分割 seg_str = ' '.join([f"{x/img_w} {y/img_h}" for x, y in ann['segmentation'][0]]) # 写入txt f.write(f"{ann['category_id']} {x_center} {y_center} {norm_w} {norm_h} {seg_str}\n") - 分层数据集划分:按类别分层抽样,将数据集划分为训练集(80%)、验证集(10%)、测试集(10%),确保每个类别在各子集的分布比例一致
- 增强适配YOLO:增强操作需同步更新YOLO标注,比如翻转后调整x_center的归一化值(1 - x_center),旋转时需重新计算标注坐标
内容的提问来源于stack exchange,提问作者Snehal Joshi




