- BrainTools - https://www.braintools.ru -
В настоящий момент я работаю над проектом по детекции дефектов дорожно‑транспортной инфраструктуры. Находимся на самом начальном этапе, подбираем модели для детекции.
Мы начинали работы с моделями детекции — как‑то по инерции с предыдущего проекта. Но этого опыта [1] и знаний (а также обученных ранее моделей) оказалось недостаточно для решения поставленных задач. Тогда мы обратились к сегментационным моделям. И сразу возник вопрос об адекватном инструменте для разметки данных.
Если вы обучали свою модель детекции или сегментации, то знаете: самое долгое — не обучение [2], а разметка. Готовые инструменты делятся на две группы. Серверные (CVAT, Label Studio) умеют всё, но их нужно разворачивать и поддерживать. Эти инструменты замечательны, но очень непростые в освоении и затратные с аппаратной точки зрения [3].
Существующие простые десктопные вроде labelImg ставятся за минуту и очень удобные в освоении, но не обладают нужным функционалом — умеют в основном размечать прямоугольники (bbox). И стало понятно, что нам нужна была середина: программа, которая запускается на ноутбуке без сервера и делает разметку bbox и полигональную разметку.
Сделали простую программку, которая делала то, что надо. Но дальше — больше: сначала понадобились повёрнутые рамки (OBB), потом маски, затем многопользовательский режим, а под конец — семантическая и panoptic‑сегментация. И всё это нужно было выгружать в форматы, которые без доработки едят YOLO, Detectron2 и Mask2Former. Так появился YOLO Annotator. Код открыт (GPL-3.0), ниже — что он умеет и как устроен изнутри.
Сначала это был чисто внутренний инструмент, и продавать его мы не собирались. Но со временем стало понятно, что он может пригодиться не только нам: многим нужно что‑то посередине между labelImg и CVAT — без сервера, но с масками, сегментацией и нормальным экспортом. Поэтому решили просто поделиться им с сообществом: программа бесплатная, код открыт под GPL-3.0. Взамен буду рад обратной связи — что неудобно, чего не хватает, где ломается.
|
Тип разметки |
Инструмент |
Для чего |
|---|---|---|
|
Прямоугольник |
BBox |
детекция |
|
Полигон |
Polygon |
инстанс‑сегментация |
|
Ломаная |
Polyline |
дороги, трещины, кабели |
|
Повёрнутая рамка |
OBB |
аэрофото, документы |
|
Ключевые точки со скелетом |
Pose |
поза, ориентиры |
|
Точка |
Point |
подсчёт объектов |
|
Метка изображения |
Classify |
классификация |
|
Маска кистью |
Brush |
объекты сложной формы |
|
Область класса |
Semantic |
семантическая сегментация, фон |
Вокруг этого — импорт готовых YOLO‑датасетов, разбивка на train/val/test, проверка качества (пустые изображения, дубли, слишком мелкие полигоны), полный undo/redo, настраиваемые горячие клавиши, русский и английский интерфейс и совместная работа через общую сетевую папку.
Обычная кисть рисует объект: каждая зафиксированная маска — отдельный экземпляр. Для семантической сегментации это неудобно: дорога на снимке — не «пять объектов‑дорог», а одна область, пусть и из нескольких кусков.
В семантическом режиме всё, что нарисовано классом road, сливается в одну область этого класса на изображении. Мазок сохраняется сразу при отпускании кнопки, а каждый пиксель принадлежит не более чем одному классу. Есть три режима:
overwrite — мазок забирает пиксели у других классов (закрасили край дороги «тротуаром» — он перешёл к тротуару);
keep — рисует только в пустые места, поэтому фон вокруг уже размеченного можно заливать широкой кистью, не боясь задеть соседей;
erase — снимает разметку.
Как устроено. Каждый слой — PNG‑маска «изображение + класс». Самое интересное — undo: при каждом мазке пишется новый файл, а старый не трогается. Отмена просто возвращает аннотации ссылку на предыдущий файл — никаких копий битмапов в памяти [4]. Мазок, затронувший сразу несколько классов (например, отобравший пиксели у соседнего), откатывается одной командой — изменения группируются в макрос QUndoStack.
Платить за это приходится лишними файлами, поэтому при открытии проекта работает уборка: файлы, на которые больше нет ссылок, сначала переносятся в _orphaned/ и удаляются только при следующем открытии. Плюс отсрочка в 24 часа — в многопользовательском режиме коллега мог только что нарисовать маску, а его JSON ещё не автосохранился.
Panoptic‑сегментация объединяет два вида разметки: счётные объекты (things — машины, люди) и аморфные области (stuff — дорога, небо). Каждый пиксель принадлежит ровно одному сегменту: конкретному объекту, области класса‑фона или «пустоте».
У каждого класса есть роль auto / thing / stuff (по умолчанию семантические классы — stuff, остальные — things). Экспорт COCO Panoptic строит карту сегментов: сначала фон, поверх — объекты; area и bbox считаются по видимой части, а объект, полностью закрытый другими, в разметку не попадает. id сегмента кодируется в цвете пикселя (R + 256·G + 256²·B), причём id выбираются рядом с цветом класса, так что PNG можно открыть и проверить глазами.
Маски в COCO можно отдать полигонами или RLE. Полигоны теряют дырки (дорога вокруг люка станет сплошной), RLE — точная попиксельная маска.
Стандартный способ закодировать RLE — pycocotools, но тянуть C‑расширение ради одной функции не хотелось. Формат несложный: маска обходится по столбцам, записываются длины чередующихся серий «фон/объект», каждая длина — как разность с длиной двумя позициями ранее, и упаковывается кусками по 5 бит в печатные символы, начиная с '0':
def _counts_to_string(counts):
out = []
for i, x in enumerate(counts):
if i > 2:
x -= counts[i - 2]
more = True
while more:
c = x & 0x1F
x >>= 5 # арифметический сдвиг, как в C-оригинале
more = (x != -1) if (c & 0x10) else (x != 0)
if more:
c |= 0x20
out.append(chr(c + 48))
return "".join(out)
Длины серий считаются векторно в NumPy. Проверка — побайтовое сравнение с pycocotools на 300 случайных масках: результат совпал полностью, а итоговый JSON целиком загружается через pycocotools.coco.COCO — тот же загрузчик, на который опираются Detectron2 и MMDetection.
|
Модель |
Формат |
|---|---|
|
Ultralytics YOLO (detect / seg / OBB / pose) |
соответствующий YOLO‑формат |
|
U‑Net, DeepLab, SegFormer |
Semantic Masks, режим Index |
|
Detectron2, MMDetection |
COCO Instances + RLE |
|
Mask2Former, OneFormer |
COCO Panoptic |
Всего форматов 12: YOLO Detect / Segment / OBB / Pose / Point / Classify, COCO Instances / Keypoints / Panoptic, Pascal VOC, LabelMe и PNG‑маски (бинарные, индексные, цветные).
Внутренний формат — собственный, а не YOLO или COCO: папка .annproj с JSON на каждое изображение и PNG для масок. Координаты нормализованы, поэтому экспорт в любой формат — чистая функция от модели данных.
Слои разделены: домен (аннотации и классы) → хранение → экспортёры → инструменты → UI. Экспортёр не знает про Qt, инструмент не знает про форматы.
Все изменения идут через команды QUndoStack — undo/redo работает для любого инструмента.
Новые инструменты подключаются плагинами: .py‑файл в папке plugins/ — и кнопка появляется в меню.
561 автотест, включая регрессионные на найденные баги.
Скачать архив релиза: https://github.com/ILYAGRISH/yolo‑annotator/releases/tag/v1.5 [5]
Поставить Python 3.10+ (рекомендую 3.13) с галкой «Add python.exe to PATH».
Запустить setup_venv.bat — он создаст окружение и поставит зависимости с проверенными версиями.
Запускать run.bat.
Честно о том, чего пока нет:
AI‑авторазметки — следующий большой шаг: SAM и YOLO в отдельном процессе, чтобы тяжёлые зависимости не попадали в основную программу;
разметки видео — в планах, через нарезку кадров;
проверено только на Windows (PyQt6 кроссплатформенный, но на Linux и macOS я не тестировал).
GitHub: https://github.com/ILYAGRISH/yolo‑annotator [6]
Релиз 1.5: https://github.com/ILYAGRISH/yolo‑annotator/releases/tag/v1.5 [5]
Каких форматов или функций не хватает в вашей разметке? Пишите в комментариях или в Issues — pull request’ы тоже приветствуются.
Автор: Ilgr
Источник [7]
Сайт-источник BrainTools: https://www.braintools.ru
Путь до страницы источника: https://www.braintools.ru/article/36726
URLs in this post:
[1] опыта: http://www.braintools.ru/article/6952
[2] обучение: http://www.braintools.ru/article/5125
[3] зрения: http://www.braintools.ru/article/6238
[4] памяти: http://www.braintools.ru/article/4140
[5] https://github.com/ILYAGRISH/yolo‑annotator/releases/tag/v1.5: https://github.com/ILYAGRISH/yolo-annotator/releases/tag/v1.5
[6] https://github.com/ILYAGRISH/yolo‑annotator: https://github.com/ILYAGRISH/yolo-annotator
[7] Источник: https://habr.com/ru/articles/1092398/?utm_campaign=1092398&utm_source=habrahabr&utm_medium=rss
Нажмите здесь для печати.