Разметка данных для Computer Vision
Качество разметки определяет потолок точности модели — никакая архитектура не исправит шумные аннотации. При этом разметка CV-данных — не просто «нарисовать рамки»: согласованность между аннотаторами, онтология классов, edge cases, форматы экспорта и QA-процесс занимают столько же времени, сколько сама разметка.
Инструменты и форматы
CVAT — основной инструмент для командной разметки. Self-hosted, поддерживает bbox, polygon, polyline, points, 3D. REST API позволяет автоматизировать создание задач и экспорт.
Label Studio — более гибкий, поддерживает мультимодальную разметку (изображения + текст + аудио), удобен для сложных задач с conditional логикой.
Roboflow — облачный вариант с версионированием датасетов и встроенной аугментацией. Удобен для быстрого старта, менее гибкий для сложных онтологий.
# Автоматизация создания задач в CVAT через API
from cvat_sdk import make_client, models
with make_client(host='http://cvat.company.local') as client:
client.login(('annotator_api', 'secret'))
# Создаём задачу с набором labels
task_spec = models.TaskWriteRequest(
name='defects_batch_042',
labels=[
models.PatchedLabelRequest(
name='crack',
color='#ff0000',
attributes=[
models.AttributeRequest(
name='severity',
mutable=True,
input_type='select',
values=['minor', 'moderate', 'critical']
)
]
),
models.PatchedLabelRequest(name='scratch', color='#ff8800'),
models.PatchedLabelRequest(name='dent', color='#ffff00'),
],
segment_size=50 # по 50 кадров на сегмент
)
task = client.tasks.create(task_spec)
# Загружаем изображения
task.upload_files(image_paths)
Inter-annotator agreement и QA
Главная проблема командной разметки — разногласие аннотаторов. IoU 0.65 между двумя разметчиками на мелких объектах — не редкость. Это напрямую влияет на обучение: если два bbox одного объекта расходятся на 20%, модель получает противоречивый сигнал.
import numpy as np
from itertools import combinations
def calculate_iou(box1: list, box2: list) -> float:
"""IoU для двух bbox [x1, y1, x2, y2]"""
inter_x1 = max(box1[0], box2[0])
inter_y1 = max(box1[1], box2[1])
inter_x2 = min(box1[2], box2[2])
inter_y2 = min(box1[3], box2[3])
if inter_x2 < inter_x1 or inter_y2 < inter_y1:
return 0.0
inter_area = (inter_x2 - inter_x1) * (inter_y2 - inter_y1)
area1 = (box1[2]-box1[0]) * (box1[3]-box1[1])
area2 = (box2[2]-box2[0]) * (box2[3]-box2[1])
return inter_area / (area1 + area2 - inter_area)
def inter_annotator_iou(annotations_by_annotator: dict) -> dict:
"""
Считаем попарное IoU между аннотаторами.
Порог для приёмки: mean IoU > 0.80 на совпадающих объектах.
"""
annotators = list(annotations_by_annotator.keys())
results = {}
for a1, a2 in combinations(annotators, 2):
boxes1 = annotations_by_annotator[a1]
boxes2 = annotations_by_annotator[a2]
ious = []
for b1 in boxes1:
best_iou = max(
(calculate_iou(b1, b2) for b2 in boxes2),
default=0.0
)
if best_iou > 0.1: # только совпадающие объекты
ious.append(best_iou)
results[f'{a1}_vs_{a2}'] = {
'mean_iou': np.mean(ious) if ious else 0.0,
'n_matched': len(ious)
}
return results
Auto-labeling для ускорения разметки
Предварительная авторазметка моделью + ручная корректура — стандарт для больших объёмов. Экономия времени 60–75% при правильном выборе модели.
from ultralytics import YOLO
import json
def auto_label_batch(
image_paths: list[str],
model_path: str = 'yolov8l-world.pt', # или дообученная модель
conf_threshold: float = 0.5,
output_format: str = 'yolo' # 'yolo' | 'coco' | 'cvat'
) -> dict:
"""
Авторазметка пачки изображений.
Высокий порог conf=0.5 — берём только уверенные предсказания,
спорные помечаем для ручной проверки.
"""
model = YOLO(model_path)
results = {}
for img_path in image_paths:
preds = model.predict(
img_path, conf=conf_threshold,
verbose=False
)[0]
confident_boxes = []
needs_review_boxes = []
for box in preds.boxes:
conf = float(box.conf)
entry = {
'bbox': box.xyxy[0].tolist(),
'class_id': int(box.cls),
'confidence': conf
}
if conf > 0.7:
confident_boxes.append(entry)
else:
needs_review_boxes.append(entry) # отправляем на проверку
results[img_path] = {
'auto_labeled': confident_boxes,
'needs_review': needs_review_boxes,
'review_required': len(needs_review_boxes) > 0
}
return results
Форматы экспорта
| Формат | Применение | Инструмент |
|---|---|---|
| YOLO TXT | YOLOv5/v8/v11 обучение | Ultralytics |
| COCO JSON | Detectron2, MMDetection | torchvision |
| Pascal VOC XML | TensorFlow Object Detection API | TF OD API |
| LabelMe JSON | Сегментация, polygons | LabelMe |
| CVAT XML | Импорт/экспорт CVAT | cvat-sdk |
Сроки и объёмы
| Тип разметки | Скорость (человек/час) | Стоимость относительно bbox |
|---|---|---|
| Bbox (bounding box) | 200–400 объектов | 1x |
| Polygon (instance segmentation) | 40–80 объектов | 4–6x |
| Semantic segmentation (по пикселям) | 2–5 изображений | 15–20x |
| Keypoints (pose) | 50–100 персон | 3x |
| Объём датасета | Срок с QA |
|---|---|
| 1000 изображений, bbox | 1–2 недели |
| 5000 изображений, bbox | 3–4 недели |
| 2000 изображений, polygon | 3–5 недель |







