Детекция волейбольного поля / корта
2026/01/08
Для автоматического анализа видео игры в волейбол желательно автоматически определять ключевые точки волейбольной площадки и сетки. Альтернатива — ручная разметка площадки для каждого видео перед началом анализа. Изучая существующие решения, наткнулся на репозиторий TennisCourtDetector. Проект 2022 года — время применения U-Net архитектуры для детекции в спорте. Небольшой простой проект со ссылкой на датасет более 8000 размеченных данных и предобученные веса — что позволяет провести собственные эксперименты.
Шаг первый - запуск tennis court detector
Клонируем репозитарий
Так как с момента последнего коммита прошло больше 3 лет (2023 г.), нужно актуализировать версии Python и библиотек. Маленький размер кода позволяет это сделать без особых проблем с использованием vibe coding
Ссылка на форк с поправленными зависимостями (в оригинальном репозитории автор давно не проявлял активность):
git clone https://github.com/asigatchov/TennisCourtDetector.git
Tracknet - для keypoints court
2023 год — пик работ в области детекции мелких спортивных объектов (теннисный мяч, волан в бадминтоне). Предположу, что на этой волне автор реализовал возможность детекции ключевых точек теннисного корта — 14 точек.
Классическая модель TrackNet, где для детекции маленького теннисного мяча подаётся 3 последовательных кадра в размере 640×360 — на выходе получаем тепловую карту среднего кадра (может быть реализация, где 3 кадра, и центральный имеет выше точность).
Dataset - залог успех
Автор предоставляет ссылки на датасет из 8000 картинок с JSON-описанием координат размеченных точек площадки. Для составления датасета использовался полуавтоматический метод: Обнаружение линий (с помощью преобразования Хафа). Источник —- Tennis Analysis using deep learning
Изучение и эксперименты
После запуска кода выяснил, что скорость работы — 1 fps на CPU и 23–36 fps на GPU (5070). Для ускорения работы было принято решение уменьшить число параметров сети за счёт уменьшения размера картинки до 512×288 (подсмотрено у современных моделей TrackNetV2/V4) и перевести кадры в чёрно-белый (1 канал вместо 3). Обучение на обрезанных данных позволило ускорить цикл обучения и немного ускорило выполнение.
Формат датасета и почему выбрал COCO
Для хорошего результата в обучении нужны размеченные данные. Ключевой момент — хорошо размеченные. Изучив данные разметки для теннисного корта, я понял, что используется пользовательский формат. Это значит, что в начале нужно разметить в один из популярных форматов, а потом конвертировать. Или модифицировать загрузчик данных под COCO-формат, а пользовательскую разметку для теннисного корта — конвертировать в COCO. COCO-формат поддерживают популярные инструменты разметки данных. Один из них — Roboflow. Roboflow имеет ежемесячный лимит кредитов, который покрывает любительские потребности. Написал CocoCourtDataset (загрузчик данных) и конвертер data_train.json → _annotation.coco.json. Тестовый цикл обучения показал, что всё проходит корректно.
Разметка волейбольного поля / корта
Так как конечная цель — работа с видео от моих любительских камер, то общедоступные датасеты не подходят. Экшен-камеры имеют рыбий глаз, и разметка от TV не подойдёт — будет работать некорректно. Первую попытку разметки я попытался сделать в Roboflow. Процесс оказался долгим, и, как выяснилось после разметки 50 кадров, данные я разметил некорректно, не разобравшись с skeleton и отрисовкой точек. Как говорится в классике — настоящие герои всегда идут в обход. Используя CV2, пишем свою среду разметки на минималках. Изначально хотел разметить 10 точек площадки (4 угла и 6 пересечений боковой линии). Затем подумал: а почему в теннисе не размечают сетку? — и добавил ещё верхние края сетки у антенн. В процессе разметки в Roboflow понял, что 8 точек размечать быстрее, чем 12, и сократил точки 3-метровых линий. Для теста я взял 15 видеозаписей игр с задней линии. Сделал автоматический механизм копирования точек. Камера неподвижна — значит, можно разметить первый кадр и переносить разметку дальше. Добавил кнопку A — авто листает видео по 50 кадров и сохраняет разметку. Кнопки N и P для перехода между точками по кругу.

yolo11m-pose - для определения ключевых точек площадки
Наличие данных позволяет проводить эксперименты с другими архитектурами сетей. Для сравнения решил попробовать обучение YOLOv11-pose. YOLOv11 от https://www.ultralytics.com/ позволяет быстро и просто дообучить нейронную сеть под свою специфику. Малое количество данных YOLO пытается компенсировать через аугментацию данных (искусственное изменение): наклоны, масштабирование, мозаика, повороты и т.д. Беглый тест показал, что можно смело брать модель — дообучать и использовать. Визуально на тестовых видео лучший результат был на конфигурации с mosaic.
data_yml = 'data/yolo-datasets/data.yaml'
results = model.train(
data=data_yml,
epochs=150, # Custom kp требует больше эпох
imgsz=1280, # Сохраняем детали корта
batch=4, # Auto-batch (или 8-16 вручную)
device=0, # GPU
patience=50,
augment=True, # Критично для вариаций кортов (освещение, угол)
hsv_h=0.015, hsv_s=0.7, hsv_v=0.4,
degrees=20,
translate=0.2,
scale=0.9, shear=10.0, fliplr=0.5,
mosaic=1.0, mixup=0.5, # Сильные аугментации для generalization
optimizer="AdamW",
lr0=0.001,
close_mosaic=20,
name="volleyball_court_yolo11m_pose_mosaic_bl",
project="runs/yolo11m_pose",
exist_ok=True
)
Ручная augumentation данных
Разметил около 2800 кадров. Если уникализировать связку камера+место установки, то получается около 20 ± уникальных кадров, на которых перемещаются игроки. Для подготовки модели к видео, которых не было в обучении, и имитации разных наклонов камеры решил сделать поворот кадра на 10 градусов в одну из сторон. Сложность заключается в том, что одновременно с кадром нужно поворачивать и ключевые точки. Важным моментом является тестирование и контроль совпадения ключевых точек после поворота. Сюрприз возник в том, что модель имеет scale=2 по размеру вход/выход: на вход 512×288, на выходе 256×144. Первый вариант модели имел низкую точность, при локализации проблемы винил несогласованность кадра и точек после поворота. Отладка и попытки вывести, что подаётся на обучение, вызывали сложности, так как требовали прокидывания параметра о режиме отладки. Простым вариантом оказалось применение flag-file:
if os.path.exist('./tmp/debug.txt'):
save_image_and_heatmaps(...)
и упрощение кода поворота
img_rotation_matrix = cv2.getRotationMatrix2D(img_center, angle, 1.0)
hm_rotation_matrix = cv2.getRotationMatrix2D(hm_center, angle, 1.0)
А так же добавление промежуточных примеров чему научилась модель на этапах валидации

В процессе экспериментов решил оформить в возможность работы с разнами видами спорта - теннис, волейбол, бадминтон.
Подробнее об этом в следующей статье.
