ИИ в логистике: отслеживаем транспортные средства на производственной территории с помощью нейросети

от автора

Привет! Меня зовут Влад Губайдулин, я full-stack разработчик в департаменте Логистика КОРУС Консалтинг. Весной на Хабре я рассказывал о том, как для дипломного проекта создавал приложение для отслеживания объектов спортивного мероприятия. Почитать об этом можно вот здесь.

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

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

Определяем цель

Я рассматриваю наше приложение как дополнение к существующим системам управления двором (YMS) и как способ более интеллектуального отслеживания транспортных средств на территории промышленных зон. 

В современных системах трекинг этапов перемещения транспортных средств (въезд на территорию/разгрузка/погрузка и так далее) в основном осуществляется с помощью вторичных инструментов: камер для чтения номеров, датчиков парковки и карточек. Меня же интересует реализация подобной функции исключительно за счет обыкновенных камер наблюдения без дополнительных «железок» — это упростит и автоматизирует процесс. 

Представьте систему видеонаблюдения, в которой отслеживание осуществляется с нескольких камер, каждая из которых имеет собственную трекинг-метку. Когда транспортное средство попадает в поле зрения камеры, она присваивает ему уникальный идентификатор. ТС перемещается и попадает в зону видимости другой камеры —  новая камера также присваивает ID. Еще есть адаптер, который сопоставляет эти идентификационные номера при выезде ТС из одного кадра и появлении его в следующем по логике кадре. На основе этой логики формируются импровизированные контрольные точки.

Камера 1

Камера 1
Камера 2

Камера 2

В качестве преимуществ такого приложения — помимо собственно автоматизации — выделю несколько функций: 

  1. Анализ фактического нахождения транспортного средства на каждом этапе разгрузки. Поможет поддерживать и оптимизировать производительность  загрузочно-разгрузочных пунктов.

  2. Мгновенная реакция в случае, если транспортное средство оказалось в запретной зоне.

  3. Учет срока пребывания ТС вне парковочного места или дока разгрузки — если машина долго стоит неподвижно, система уведомит о возможной поломке. 

  4. Идентификация свободного парковочного места или дока разгрузки — следующее транспортное средство можно вызвать на место автоматически..

  5. Расчет скорости движения транспортного средства: при превышении допустимой скорости можно провести беседу с водителем при выезде.

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

Раскладываем инструменты

Тут мы делаем DataScience, поэтому, разумеется, Python — наш лучший друг.

Для хранения данных используем SQLite, простая и легкая база данных.

Чтобы не заморачиваться с запросами к базе, а сразу работать с нужными объектами, возьмем SQLAlchemy.

Теперь перейдем к более интересной части — отслеживанию объектов в видео. Здесь на помощь приходят две мощные библиотеки: ByteTrack и YOLOv8.

ByteTrack — это инструмент, который помогает следить за несколькими объектами в видео. Делает это легко и эффективно, даже если объекты частично скрыты или находятся далеко от камеры.

YOLOv8  — это одна из самых современных моделей для обнаружения объектов, известна своей скоростью и точностью, что делает её идеальной для задач, выполняемых в режиме реального времени, таких как видеонаблюдение или автономное вождение. 

И, конечно, библиотека OpenCV — это отличный инструмент для работы с изображениями и видео. Она позволяет делать практически всё: от простого чтения и записи видео до сложных операций, таких как распознавание лиц или фильтрация изображений.

С ее помощью вы можете изменять размер, поворачивать, улучшать качество изображения, определять контуры объектов.  И все это даже иногда работает.

Конвейер обработки видеоизображения представлен в листинге 1. В нем можно найти пример подключения YOLO и ByteTrack, а также отрисовку с помощью OpenCV.

Листинг 1

async def main(self, is_show_frames):    device = 'cuda' if torch.cuda.is_available() else 'cpu'    print(f'Using device: {device}')    model = YOLO('yolov8l.pt').to(device)      cap = cv2.VideoCapture(self.VIDEO_PATH)      ret, frame = cap.read()      byte_tracker = BYTETracker(BYTETrackerArgs.BYTETrackerArgs())      while ret:        results = model(frame)[0]        detections = Detection.Detection.from_results(            pred=results.boxes.data.cpu().numpy(),            names=model.names)          car_detections = filter_detections_by_class(detections=detections, class_name="car")        truck_detections = filter_detections_by_class(detections=detections, class_name="truck")        detections = car_detections + truck_detections          tracks = byte_tracker.update(            output_results=detections2boxes(detections=detections),            img_info=frame.shape,            img_size=frame.shape        )          tracked_detections = match_detections_with_tracks(detections=detections, tracks=tracks)          for detection in tracked_detections:            tracked_objects_aud_id = await Recording().record_tracks_async(detection, self.CAMERA, self.AREA_EXIT)              if is_show_frames:                cv2.rectangle(frame,                              (int(detection.rect.x), int(detection.rect.y)),                              (int(detection.rect.x + detection.rect.width), int(detection.rect.y + detection.rect.height)),                              (255, 255, 255), 2)                  cv2.putText(frame,                            f'{detection.class_name}_id#{tracked_objects_aud_id}',                            (int(detection.rect.x), int(detection.rect.y) - 10),                            cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 0, 255), 2)          if is_show_frames:            if self.IS_PARKING_EXIST:                parking_color = self.COLOR.get_current_parking_color(tracked_detections, self.AREA_PARKING_PLACE)                  # add bounding box for parking                cv2.rectangle(frame,                              self.AREA_PARKING_PLACE[0],                              self.AREA_PARKING_PLACE[1],                              parking_color, 2)                cv2.putText(frame,                            f'parking_place',                            self.TEXT_PARKING_PLACE,                            cv2.FONT_HERSHEY_SIMPLEX, 0.6, parking_color, 2)              # add bounding box for exit            cv2.rectangle(frame,                          self.AREA_EXIT[0],                          self.AREA_EXIT[1],                          (0, 0, 150), 2)            cv2.putText(frame,                        f'exit_place',                        self.TEXT_EXIT,                        cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 128), 2)              cv2.namedWindow('frame')            cv2.imshow('frame', frame)          k = cv2.waitKey(33)        if k == 27:            break          ret, frame = cap.read()      cap.release()    cv2.destroyAllWindows() 

Определяем архитектуру

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

На производственной площадке установлены IP-камеры, которые контролируют парковочные зоны и зоны загрузки. Каждая из камер передаёт фреймы на сервер для последующей обработки. На сервере применяется алгоритм, использующий нейронные сети для выделения и анализа интересующих объектов.

  • Новый объект: Если система обнаруживает объект с новым идентификатором (ID), алгоритм пытается сопоставить его с транспортным средством, которое имеет схожее предыдущее местоположение и последнюю запись в пределах допустимого временного интервала.

  • Старый объект: Если объект уже имеет существующий ID, система просто обновляет его местоположение.

Для переиндексации объектов используется таблица exit_zones, содержащая информацию о присутствии объектов в ассоциативных границах камер. Эта таблица включает ID последнего транспортного средства в границе, ID камеры с общей границей и статус наличия транспортного средства в данной зоне.

Например, если объект покидает зону видимости Камеры 1 и попадает в зону видимости Камеры 2, данные с Камеры 2 обрабатываются для определения, является ли этот объект новым для неё. Если да, система проверяет, отслеживался ли он другими камерами. В случае положительного результата происходит переиндексация. Если нет — объекту присваивается новый индекс. Для старых объектов просто обновляется информация о местоположении.

Все данные передаются на интерфейс и доступны для просмотра в хранилище. К базе данных можно подключать другие системы через API или брокер сообщений.

 Функциональные возможности системы

Функционально система делится на две части: 

  1. Ведение журнала о перемещении объектов на видео; 

  2. Комплексное отслеживание объектов на территории по нескольким камерам с учетом перехода объектов из области видимости одной камеры в другую.

Первая часть на данный момент реализована целиком. Спроектирована UML диаграмма классов, которая легла в основу схемы базы данных. Для минимальной работы системы необходимо три класса: 

  • камеры (cameras); 

  • отслеживаемые объекты (tracked_objects_aud); 

  • ассоциативные границы (exit_zones). Класс ассоциативных границ необходим для переиндексации объектов при переходе с одной камеры на другую. 

Вторая часть — собственно отслеживание объектов — реализована частично. Уже готов алгоритм, который отвечает за переиндексацию отслеживаемых объектов при переходе объекта с одной камеры на другую. Он вызывается на каждом обрабатываемом кадре для любого обнаруженного объекта после записи нового транспортного средства или актуализации данных старого в базе данных.

Осталось доработать момент с расчетом идентичности двух обнаруженных объектов и принятием решения об индексации. То есть, сейчас алгоритм довольно‑таки глуп: при пересечении границ камер он любой машине присвоит старый индекс, а суть конечной идеи, чтобы он точно мог определить, что в зону видимости заехало новое транспортное средство или, что мы продолжаем наблюдать за старым.

Сейчас думаю о том, чтобы сделать собственную нейросеть, которая будет сверять по свертке два объекта и выдавать % соотношения их идентичности. Пока все на уровне эксперимента.  

Такая система может быть запущена на любом производстве. Достаточно только вручную настроить ассоциативные зоны-границы камер — остальное она определит сама. Ахиллесова пята решения — производительность, так как для нормальной работы системы из коробки нужны мощные ресурсы: цп, видеокарта, оперативка. В качестве компромисса можно рассмотреть ограничения: обрабатывать каждый n-ый кадр, вместо того, чтобы обрабатывать каждый. При таком подходе нужно будет рассчитать, сколько кадров можно пропустить.

Псевдокод

Метод, ответственный за переиндексацию отслеживаемых объектов при переходе объекта с одной камеры на другую, вызывается на каждом обрабатываемом кадре для любого обнаруженного объекта после записи нового транспортного средства или актуализации данных старого в базе данных. Алгоритм переиндексации представлен псевдокодом А1.

Алгоритм А1

Procedure actualize_exit_zones_data   Ввод exit_area_rect – координаты выделяющей рамки ассоциативной границы Ввод transport_rect – координаты выделяющей рамки транспортного средства Ввод camera_id – идентификационный номер камеры, с которой пришёл кадр If exit_area_rect и transport_rect пересекаются then             Получение из БД текущее состояние модели ассоциативной границы из класса exit_zone             If значение tracked_objects_aud_id НЕ равно текущему транспортному средству then                     Присвоение tracked_objects_aud_id значение id текущего транспортного средства                    Присвоение флагу is_empty значение 0             End    End   Else if значение tracked_objects_aud_id для ассоциативной границы из класса exit_zone равен текущему транспортному средству then              Присвоение флагу is_empty значение 1              Получение пар id объектов и id ассоциативной границ, которые связаны, при условии, что связанная граница также имеет флаг is_empty равный 1              If такая пара ассоциативных границ существует then                     Перезапись координат и камеры в более старой модели для tracked_objects_aud на актуальные, новый id удаляем из таблицы                    Присвоение парам ассоциативной границ last_tracked_objects_aud NULL и флагу is_empty 1.             End    End End actualize_exit_zones_data 

Разрабатываем

Разработка шла по таким этапам: 

  • Перенос имеющихся методов из пет-проекта. 

  • Проектирование ER-модели приложения.

  • Реализация алгоритма переиндексации. 

  • Реализация и внедрение нейронной с расчётом идентичности двух обнаруженных объектов и принятием решения об индексации (в процессе).   

На этапе реализации механизма переиндексации столкнулся со сложностями. Во-первых, не был плотно знаком с ORM SQLAlchemy, из-за чего при разработке допускал ошибки. Во-вторых, изначально не придумал «триггеры», которые должны инициализировать переиндексацию. Сейчас они есть и занесены в отдельную таблицу, которая фиксирует входы и выходы из границ камер. Когда описывал принципы работы системы, рассказывал про нее.

Определяем дальнейшие шаги

Из планов: 

  • реализовать и внедрить нейросеть для расчета идентичности двух обнаруженных объектов и принятием решения об индексации (когда удастся это сделать, обязательно поделюсь результатами);  

  • реализация API приложения и разделения монолитного приложения на клиент и сервер.

Подчеркну мой личный итог: из пет-проекта, разработанного для защиты дипломной работы, вырос (почти) полноценный, применимый в реальном бизнесе инструмент. Надеюсь, что быстро справлюсь со всеми перечисленными сложностями и доработаю его. Будет здорово, если мой пример подтолкнет кого-то из читателей к развитию их пет-проектов или к созданию таковых.  

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


ссылка на оригинал статьи https://habr.com/ru/articles/854972/


Комментарии

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

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