Как соседняя машина «заняла» свободное место на парковке. rf-detr.. rf-detr. yolo.. rf-detr. yolo. компьютерное зрение.. rf-detr. yolo. компьютерное зрение. сегментация.
Жёлтый контур свободного места между белым седаном и тёмным фургоном

Жёлтый контур свободного места между белым седаном и тёмным фургоном

Посмотрите на кадр. Белый седан стоит слева от жёлтого контура. Из-за угла обзора камеры его силуэт закрывает 49% площади соседнего парковочного места. Для водителя очевидно, что место справа свободно, но алгоритм, хотя и правильно нашёл машину, всё равно решил, что место занято.

Ниже расскажу о том, как система поиска свободных мест на парковках прошла несколько архитектурных итераций: от ошибок ранней разметки и экспериментов с кропами до построения 3D-призм и поиска зазоров в неразмеченных рядах.

Итерация 1. Где ошибалась сама карта при 2D-анализе

Первая версия системы находила автомобили с помощью yolov8s-seg.pt и напрямую сравнивала их маски с размеченными зонами. Сегментационная маска точнее обводит кузов и захватывает меньше лишнего асфальта, чем прямоугольная рамка (bounding box). На первых тестах такой подход выглядел вполне рабочим.

Однако при сверке снимков с одной и той же камеры за разные дни вскрылась проблема с самими зонами. Оказалось, что часть ранней разметки была сделана с оглядкой на стоящие в кадре машины — фактически «по кузовам». На другом кадре автомобиль вставал чуть иначе или менялись его габариты, и нарисованный контур уже плохо описывал реальные границы места на земле.

После этого я разделил разметку и анализ на две задачи. Теперь границы мест подтверждаются в редакторе строго по линиям на асфальте, бордюру и общей геометрии ряда. А занятость определяется на каждом новом снимке уже по готовой неподвижной карте.

Фрагмент парковочного ряда. Жёлтые линии отмечают границы мест и скрываются за силуэтами машин.

Кадр из обучающего набора модели занятости. Жёлтым отмечены реальные границы мест на асфальте

Итерация 2. Что потерялось при анализе кропа

Когда точная карта мест уже есть, можно показывать лёгкой нейросети только фрагмент кадра вокруг каждого места. В эксперименте для телефона я вырезал фрагмент по прямоугольной рамке полигона с 12% контекста, приводил его к размеру 160 × 160 и подавал в классификатор MobileNetV3-Small. Два порога отделяли уверенные ответы «свободно» и «занято», а между ними модель возвращала статус «не определено».

Для базового обучения я взял публичный набор CNRPark+EXT, содержащий около 157 тысяч размеченных кропов и полные кадры с координатами мест (на том же сайте выложены готовые mAlexNet и AlexNet в Caffe, которые также отвечают «свободно» или «занято» для заданного места).

Обучение классификатора

AUC на CNRPark+EXT

AUC на рабочих камерах

4 000 кропов, 1 эпоха

0,9967

0,8177

16 000 кропов, 2 эпохи

0,9994

0,7303

AUC показывает, насколько качественно модель разделяет свободные и занятые места по своим оценкам ещё до выбора порога.

На тестовой подвыборке из 8 000 кропов CNRPark+EXT второй прогон дал более высокий AUC, а на дворовых камерах — заметно более низкий. При этом в первом прогоне выбранные пороги оставили неопределёнными 66 из 175 примеров (свободных в этой первой проверке было всего 13). Между прогонами изменились и объём данных, и число эпох, но главная проблема оказалась фундаментальной.

Классификатор видит только само место и небольшой участок вокруг него. По такому кропу сложно надёжно определить, стоит ли машина на проверяемом месте или в его контур попал капот соседней машины из-за ракурса камеры. Поэтому анализ вернулся к полному кадру: небольшая модель начала получать признаки всего окружения — долю перекрытого места, положение нижней части машины и количество соседних автомобилей.

Итерация 3. Что сломалось и починилось при смене детектора

Поскольку детектор только выдаёт маски машин, а занятость вычисляется отдельным алгоритмом, сегментатор удалось заменить без переписывания логики оценки занятости. Я перешёл на архитектуру RF-DETR Seg: для iPhone использовался экспорт в Core ML, а для CPU на сервере — в ONNX.

Причина перехода

После yolov8s-seg.pt я попробовал YOLO26-seg, несмотря на хорошие показатели отказался от него из-за лицензии AGPL-3.0, под которой Ultralytics распространяет модель.

Из четырёх вариантов детектора я сначала выбрал самый быстрый — на трёх архивных кадрах он показал наименьшую задержку и на iPhone, и на сервере. Однако на живом ночном кадре обнаружилась проблема: при стандартном пороге уверенности 0,5 детектор пропустил тёмные машины, и два занятых места получили ложный статус «свободно». На том же JPEG при снижении порога до 0,25 маски появились, и оба ответа исправились. В итоге порог 0,25 стал единым для обеих платформ.

Во время миграции вскрылись и две программные ошибки в обработке геометрии:

  • На сервере: полигоны контуров переводились в одни координаты, а описывающие прямоугольники (bounding boxes) вокруг них оставались в исходных координатах кадра.

  • На iPhone: жесткая проверка отбрасывала результат целиком, если рамка оказывалась чуть шире кадра. Детектор может вернуть слегка выходящую за край рамку вместе с абсолютно корректной маской внутри кадра — из-за этой фильтрации полезные маски на краях терялись.

В итоге для объёмной версии я выбрал более крупный вариант детектора RF-DETR Seg Large с входом 504 × 504, а предсказанные маски сохранил для контрольного сравнения.

Итерация 4. Объёмная геометрия: что делать, когда кузов перекрывает соседнее место

В кадре крыша и капот могут проецироваться со смещением относительно колёс. Чтобы понять, виден ли реальный низ машины на асфальте, алгоритм смотрит на узкую контрольную полоску сразу под маской:

  • Если ближние машины закрывают меньше 20% этой полоски, низ считается видимым. Опору автомобиля оценивают по нижней полосе самой маски (её высота составляет 28% от общей высоты силуэта).

  • Если закрыто 20% или больше, низ перекрыт соседом, и алгоритм переходит к проверке видимой части машины в проекции 3D-призмы.

Слева голубая нижняя полоса маски пересекается с жёлтым контуром места. Справа видимая маска дальней машины сравнивается с зелёной частью призмы после вычитания ближней машины.

Слева фиолетовым выделено пересечение нижней полосы (28% высоты маски) с контуром места на земле. Справа рыжая полоска показывает, где маска ближней машины перекрыла область сразу под дальней — заштрихованная часть призмы исключается из сравнения

3D-призма здесь — приближение в координатах кадра. За основание алгоритм берёт четырёхугольник места, копирует его и сдвигает копию вверх. Величина сдвига в пикселях зависит от длин сторон места в кадре. Из двух четырёхугольников строится общий выпуклый контур. По нему алгоритм оценивает, какая часть силуэта приходится на область над местом и какую долю этой области заслоняет ближняя машина.

Один снимок в двух вариантах. Слева контур места на земле, справа над тем же местом построена призма.

Слева — плоский контур на асфальте, справа — построенная над ним проекция объёмной призмы.

Схема алгоритма оценки занятости с 3D-призмами

  1. На входе: снимок с камеры, карта подтверждённых мест и маски машин от RF-DETR Seg Large.

  2. Расчёт признаков: если низ виден, алгоритм измеряет, какая доля нижней 28%-й полосы попала в контур на земле, а также учитывает общее покрытие места и положение нижней точки маски по высоте контура. Если низ закрыт, из 3D-призмы вычитается маска ближней машины, а для пересечения с видимой маской дальней машины вычисляются две доли — от самой маски и от оставшейся части призмы.

  3. Сопоставление пар: привязка начинается с пар «маска — место» с наибольшей оценкой. Одна маска может быть привязана максимум к одному месту. Признаки обычного плоского перекрытия также сохраняются, поэтому реальный заезд соседней машины за линию разметки всё ещё учитывается.

  4. Итоговое решение: классификатор получает 17 признаков и оценивает вероятность того, что место свободно. Рабочий порог рекомендации в объёмной версии — 0,83.

Что изменилось на 1 002 кадрах и почему не прижился гибрид с кропами

В контрольное сравнение вошли 1 002 кадра с ручной разметкой. Всего получилось 6 041 наблюдение, каждое из которых соответствует одному месту на одном кадре. В 178 наблюдениях место было свободно. Обе версии получили одни и те же кадры, полигоны мест и сохранённые маски RF-DETR Seg Large. Веса и пороги каждой модели оставались фиксированными.

Метрика (6 041 наблюдение)

Прежняя модель

Объёмная

Найдено из 178 свободных

135

140

Занятое место назвали свободным (False Positive)

52

33 (−19)

Пропущено свободных (False Negative)

43

38 (−5)

F1 для класса «свободно»

74,0%

79,8%

Метрика F1 учитывает и точность рекомендаций, и долю найденных свободных мест. Главное изменение — ложных срабатываний «свободно» стало на 19 меньше (для водителя это самая чувствительная ошибка, из-за которой он зря едет к занятому месту). При этом объёмная версия добавила десять ошибок там, где прежняя отвечала правильно, а на ночных кадрах с 20:00 до полуночи обе версии пропустили все 12 наблюдений свободных мест.

Проверка масок от SAM 3

Отдельно я проверил, что будет, если подать той же объёмной модели маски от SAM 3, модели Meta*. На тысяче кадров модель правильно распознала на шесть свободных наблюдений больше, но число ложных «свободно» выросло с 33 до 42. Итоговый F1 практически совпал, поэтому в рабочем варианте остался прежний детектор.

Попытка объединить 3D-призмы и оценку по кропу

На тех же 1 002 кадрах я проверил, улучшит ли объединение двух подходов результат. К 17 признакам объёмной модели я добавил 18-й — оценку по кропу от классификатора из первого прогона на 4 000 примерах. Веса классификатора оставались фиксированными, дообучалась только финальная модель принятия решений.

  • На одном адресе, отложенном для теста, F1 для свободных мест вырос с 83,6% до 86,2%, а ложных «свободно» стало 10 вместо 11.

  • Но когда я по очереди оставлял каждую из шести групп адресов для теста и подбирал вариант объединения на остальных, F1 гибрида просел до 65,6% против 79,8% у чистой объёмной модели.

  • В дневном интервале с 10:00 до 16:00 гибрид с 18-м признаком нашёл лишь 43 из 80 свободных мест (объёмная модель — 72). С 20:00 до полуночи гибрид нашёл 5 из 12 свободных наблюдений, но 7 раз назвал занятое место свободным (переобученная модель без кропа нашла 1 место при тех же 7 ложных ответах, тогда как рабочая объёмная модель пропустила все 12, но не дала ни одной ложной рекомендации).

  • При включении гибридного варианта только в ночном окне общий F1 изменился с 79,8% до 79,9% ценой роста ложных «свободно» с 33 до 40. В итоге в продакшене осталась чистая объёмная модель.

Практические сценарии: зазоры в ряду и работа при шатдаунах

Два места заняты, а между ними есть зазор

Отдельный интересный кейс нашёлся на продольной парковке вдоль бордюра. Машины там часто паркуются со смещением: одна заняла край первого места, другая — край соседнего. Полностью свободного слота по линиям разметки нет, но между бамперами вполне хватает длины для парковки ещё одного автомобиля.

Между двумя машинами зелёным отмечен возможный зазор, который пересекает жёлтые границы двух мест.

Жёлтым показаны два размеченных места. Зелёным — отдельное динамическое окно, которое алгоритм предложил между машинами, оценив вместимость по автомобилям в том же ряду.

Для таких случаев я добавил непрерывную проверку вдоль ряда. Алгоритм ищет пустой промежуток, учитывает перспективу, сравнивает длину с типичным автомобилем из этого же ряда и оставляет безопасный запас. Затем над зазором строится собственная 3D-призма, чтобы оценить, свободен ли зазор. Статусы исходных жёлтых мест при этом не меняются, а найденное окно показывается водителю как отдельный результат.

Как опросить камеры в условиях ограничения мобильного интернета

Если при региональных ограничениях мобильного интернета приложение теряет прямой доступ к API, то мессенджер MAX из «белого списка» остаётся доступен, камеры можно опросить через чат-бота. В боте можно выбрать нужную камеру и запросить свежий снимок или запустить проверку всех доступных точек.

Дальнейший R&D: детекция выезда по фарам и авторазметка камер

  • Можно ли заметить выезд по фарам? Я проверял гипотезу о том, что включение фар ночью может служить ранним сигналом освобождения места. Однако на одиночных ночных кадрах по яркости внутри маски сложно надёжно отличить фару от светлого кузова под фонарём или блика на мокром асфальте. К тому же водитель может просто греть машину со светом и никуда не уезжать. Поэтому для проверки гипотезы я перехожу к коротким сериям кадров, на которых видно реальное время от включения фар до начала манёвра.

  • Как упростить добавление новой камеры? Сейчас при подключении камеры оператор вручную рисует границы каждого парковочного места. Чтобы свести эту задачу к быстрой проверке черновика, система может сама предлагать карту мест на основе архивных кадров и контуров автомобилей — отслеживая повторяющиеся позиции стоящих машин (по аналогии с методом Almeida и соавторов в Vehicle Occurrence-based Parking Space Detection). Смена машин открывает ранее закрытые участки земли, а учёт общей перспективы и границ парковочной полосы помогает согласовать соседние места между собой даже во дворах без видимой разметки.

Самыми сложными пока остаются ночные кадры. В контрольном тесте после 20:00 обе версии пропустили все 12 свободных мест. Буду рад конструктивной критике и идеям, что ещё стоит проверить или добавить.

* Meta Platforms Inc. признана экстремистской организацией и запрещена в России.

Автор: zona7o

Источник