You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

目标检测项目图像标注全流程及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

火山引擎 最新活动