AI (Computer Vision) для реальной жизни (или кто для кого готов)

от автора

Профессия «плотник» полезна в обычной жизни, а что можно сказать о «программисте»? Когда государственной политикой является цифровизация, то правительство должно понимать: цифра она везде цифра! И в обычной жизни придется учитывать и такие истории.

Но сначала, чтоб не тратить время «продвинутых» хабберчан, краткое резюме:
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 показала лучшие результаты, определив все автобусы и даже заметила мотоциклиста! А вот самая продвинутая модель решила что здание это автобус! Но что особо удивляло, автобусы, расположенные горизонтально (внизу, который) хуже всего распознавали, и только младшая модель приняло его как грузовик.

сравнение качества распознования моделей Yolo 8m, 8l и 8x

сравнение качества распознования моделей Yolo 8m, 8l и 8x

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

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

сравнение качества распознования моделей Yolo 12n и 12l

сравнение качества распознования моделей Yolo 12n и 12l

Опции и настройки все были стандартные и одинаковыми. Надо попробовать обучить свою модель. Информация доступна в доке по 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.

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

результаты распознания обученной модели на базе yolo 12n

результаты распознания обученной модели на базе yolo 12n

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

результаты обучения модели на базе yolo 12n

результаты обучения модели на базе yolo 12n

Результат более чем устраивал и я натравил модель на архив фотографий. Стоит упомянуть, что есть такой талант у меня (кроме скромности), находить ошибки. А другими словами — всегда вляпаюсь во что-то! И тут нашел особенность: по началу, я анализировал каждое фото по отдельности. Но потом, оптимизируюя код, нашел удобную возможность сразу в модель отдавать список файлов. И тут сюрприз: если по одному распознание 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/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *