Профессия «плотник» полезна в обычной жизни, а что можно сказать о «программисте»? Когда государственной политикой является цифровизация, то правительство должно понимать: цифра она везде цифра! И в обычной жизни придется учитывать и такие истории.
Но сначала, чтоб не тратить время «продвинутых» хабберчан, краткое резюме:
1. уровень технической информации = junior
2. стек = python, ultralytics, YOLO (различных версий)
3. тема = распознование объектов, обучение модели
4. социальная польза = забота об экологии в городе Москва
История эта началась в нулевых, когда проходя мимо круга разворота автобусов, что находится у дома, я заплутал между громадного их количества, стоящих с включенными двигателями и чадящим прямо под окнами жителей.

Как видите (фото 25 года), ситуация особо не поменялась, хотя было заверение от мэрии Москвы (даже официальный ответ есть), что всем дали втык, провели беседу с водителями, ведь для них организована отдельная площадка (в 500 метрах) с местом для приема пищи, туалетом (это отдельная статья недовольства).
Ситуация с электронным обращением в Мосгортранс повторилась, ответ пришел аналогичный: такого быть не может, мы белые и пушистые, наши водители самые лучшие и никогда не нарушают правил (на фото, два автобуса, что справа, стоят в зоне действия знака «остановка запрещена»)
Но ближе к компьютерам, а то не статья, а жалоба получается! Решив подкрепить обращение фактами, заснял на GoPro фото с интервалом 30 секунд. Батарейки хватило на 3 часа 52 минуты (465 кадра). Далее, не руками же считать автобусы, решил подкинуть вопрос популярным ныне AI. На Хабре нашлась хорошая статья, которая дает пошаговую инструкцию как начать работать с моделями, провести обучение и получить результаты. Но как и многие тут статьи, она оказалась переводной (адаптированной). Источник (eng) содержит больше деталей и по структуре более логичен, что помогло в дальнейшем.
Переходим к делу! Всегда удивляло, когда в статьях пишут «pip install….» выделяя для этого много строк и внимания! Но тут обойти не могу без внимания задачу установки.
Во первых, я уже перешел на uv — uv pip install ultralytics
А во вторых, пакет этот просто так не заработает, вам надо откатиться по numpy до первых версий, так как Ultralytics собран на них и нормально со свежими пакетами работать не будет uv pip install "numpy<2"
Хотя по неведомым причинам при установки Ultralytics они сами подкачивают последний пакет.
Начинаем грузить рекомендованные модели:from ultralytics import YOLO
#model = YOLO('yolov8m.pt')
#model = YOLO('yolov8l.pt')
model = YOLO('yolov8x.pt')
results = model.predict('bus_test.jpg')
оставил комментариями примеры разного уровня моделей (глубина, размер), которые тестировал. Стоит сделать первое замечание, которое меня, как новичка в AI, удивило: более тяжелые модели хуже распознают автобусы на фото!
Слева на право модели 8m, 8l, 8x. И как видно, модель medium показала лучшие результаты, определив все автобусы и даже заметила мотоциклиста! А вот самая продвинутая модель решила что здание это автобус! Но что особо удивляло, автобусы, расположенные горизонтально (внизу, который) хуже всего распознавали, и только младшая модель приняло его как грузовик.

Я не стану повторять код как вытаскивать результаты распознания из модели, подкрашивать объекты — это все есть по ссылкам выше (кстати в 12й версии подкраска может быть сделана автоматом). А вот посмотреть ответ по объектам от моделей — стоит, в них есть много полезной информации, что и заставило покопать глубже.
Оказалось, что v8 далеко не самая свежая и на март 2025 доступна v12. Запускаем заново анализ и смотрим чем может нас удивить новая модель. При относительно быстрой работе, 12я дала хуже результаты по всем объектам! Некоторые автомобили стали телефонами!

Опции и настройки все были стандартные и одинаковыми. Надо попробовать обучить свою модель. Информация доступна в доке по Yolo
Для обучения потребовалось создать картинки с разметкой, подготовить наборы для разных этапов обучения и подождать некоторое время, пока модель все это скушает. Отмечу рекомендованную в статьях программу RoboFlow и если меня не обманули, ссылка приведет (после регистрации) к рабочему набору для обучения модели, который публичный. Там же можно обучить и разные модели других производителей, но я использовал сервис только для разметки и подготовки yaml файла для обучения.
По ссылке, можно будет скачать сам набор, который подсовываем в модель и ждем:
model = YOLO("yolo12n.pt")
results = model.train(data="data.yaml", epochs=100, imgsz=640)
В моём случае, для 100 эпох, обучение заняло около 20 минут:
Ultralytics 8.3.93
Python-3.12.6 torch-2.2.2 CPU (Intel Core(TM) i5-1038NG7 2.00GHz)
100 epochs completed in 0.362 hours.
Результат меня очень порадовал! Все автобусы в архиве фотографий были распознаны корректно! И даже двойные! Но на будущее, нужно больше обучающих данных и обязательно разнородных — как по картинке (освещение, углы) так и ракурсы. Но в нашем случае мы имеет дело с архивом фотографий из одной точки и одного места.

Результаты обучения можно найти по пути runs/detect/train/weights
вместе с кучей данных и результатов для проведения более тонкой настройки и анализа

Результат более чем устраивал и я натравил модель на архив фотографий. Стоит упомянуть, что есть такой талант у меня (кроме скромности), находить ошибки. А другими словами — всегда вляпаюсь во что-то! И тут нашел особенность: по началу, я анализировал каждое фото по отдельности. Но потом, оптимизируюя код, нашел удобную возможность сразу в модель отдавать список файлов. И тут сюрприз: если по одному распознание 465 файлов занимало 2 минуты 30 секунд, то передав списком, модель уходила в несознанку.

Но если передать на predict просто директорию, то модель так же обучается (и да, на скорость это не влияет, те же 2 с половиной минут)

По коду обнаружил, что не смотря на то, что модель рассчитана на распознание только одного объекта (nc=1) при обучении (как и распознании) попадаются данные, что все 64 объекта проходят верификацию. Не стал уделять времени разбирательству этой особенности, но осадочек остался. Стоит еще посмотреть работу с размерами как источников, так и файлов обучения, там тоже есть нюансы.
Получив детали по каждой фотографии и по каждому автобусу на ней, я принялся подсчитывать результаты.

Наверняка это известно всем, но для меня стало откровением: один и тот же автобус, на разных фотографиях, сделанных со штатива (без изменения ракурса, локации и т.п.) могут иметь (и чаще всего имеют) разные координаты! Даже по нормированным данным. Отличия минимальны — может быть 1(2) пикселя, иногда до 10, но разные!
Глаз зацепился за поля id и is_track и выяснилось, что при анализе видео потока можно по id четко идентифицировать объект, который «ведет» система. Но в случае с фотографиями мы переходим в область обнаружения идентичного объекта на двух снимках, что усложняет работу.
По хорошему, стоило организовать видео съемку разворотного круга и в режиме онлайн считать более четко данные по каждому автобусу, что попадает в поле зрения. Но лень побеждает и я делаю простое допущение: если сумма отклонений координат по объекту не превышает 1% то это один и тот же автобус.
def compare_busses(bus1, bus2, acc = 0.01):
diff = 0
for corner in range(0,4):
diff += abs((bus1[corner] - bus2[corner]) / (bus1[corner] + bus2[corner]) / 2)
return round(diff,2) <= acc
Далее, сравниваем две фотографии на количество одинаковых автобусов простым перебором (в photo, помимо координат, передается еще и точность распознания, но так как у меня объект в модели только один, особого внимания я ей не уделяю):
def compare_photos(photo1, photo2):
stand_bus = 0 for bus1, acc1 in photo1:
for bus2, acc2 in photo2:
if compare_busses(bus1, bus2):
stand_bus += 1 return stand_bus
Извиняюсь перед любителями красоты кода: задача стояла быстро получить результат без особой оптимизации. Ну а дальше просто перебираем все картинки и смотрим сколько автобусов на них занимают те же самые места, умножаем это количество на 30 секунд (интервал между фотографиями) и получаем время простоя.
def bus_timer():
bus_num = 0 for i in range(len(archive)-1):
bus_num += compare_photos(archive[i].get('busses'), archive[i+1].get('busses'))
return bus_num
Я, конечно, могу ерунду какую-то написать, возможно даже и ошибаюсь в корректности подсчета, но вроде не сильно от правды далеко. А сомнения у меня от результата:
За 3 часа 52 минуты контроля, на разворотном круге простояли с включенным двигателем автобусы 10 часов 50 минут и 30 секунд!
Если взять 6 литров в час (как минимум) работы холостого хода, то это ~66л ( по цене 69.74 руб) получаем ~ 4500 руб. Дальше умножайте на рабочий день и дни в месяце, году и получайте эффективность управление транспортом в городе Москва. С допущениями по дням, разному графику, получаем минимум 3,8 миллиона рублей ушло на ветер!

Но для моей задачи, показатель работы двигателя в 10 часов под окнами дома более существенный! Поэтому уже с более весомыми аргументами, продолжу общение с Мосгортрас.
«Ничто не может остановить мотивированную морскую свинку» © Чип & Дейл.
ссылка на оригинал статьи https://habr.com/ru/articles/895048/
Добавить комментарий