«Мы всего лишь хотели пофиксить баги в своем продукте, а психанули и создали аналог одной из библиотек» — CV-инженеры CodeInside.
Итак, в созданной нами системе мониторинга транспортного потока Smart Traffic System доступен функционал по распознаванию номерных знаков автомобилей.
Для работы этой функции ранее мы использовали библиотеку автоматического определения и распознавания автомобильных номеров — opensource-решение Nomeroff-net.
Однако, во время пользования этой библиотекой, столкнулись с долгим запуском и inference + библиотека занимала большое количество оперативной памяти. Так как мы решали эти проблемы в коммерческом проекте, кода здесь не будет. И вместе с тем, в статье указали репозиторий, конкретные шаги решения, чтобы при возникновении аналогичных проблем, вы смогли адаптировать его под свой проект.
Введем в контекст
На связи CodeInside — аутсорсинговая и продуктовая ИТ-компания. В портфеле разработанных нами продуктов есть решение Smart Traffic System (далее — STS) — ПО для сбора и анализа данных о транспортных потоках в режиме реального времени по данным видеокамеры. Система помогает городу или интегратору анализировать и распределять транспортную нагрузку, сокращая издержки при помощи машинного зрения.
Решение позволяет:
определять и подсчитывать 10 типов транспортных средств по на определенном участке дороги (перекрестки и прямые) и пешеходов;
определять направления движения автомобилей;
передавать данные во внешние системы с подсчитанным трафиком для дальнейшей обработки системами.
Дополнительная функция: STS.ГРЗ — определение ГРЗ на прямых участках дороги.
Мы решили включить STS.ГРЗ во всю существующую систему STS, предварительно доработав ее.
Да, мы знаем, что существует огромное количество аналогов по распознаванию ГРН, работающих на CPU. Однако, целевая аппаратная платформа STS — нейроускорители из серии Jetson, где CPU относительно слабый, поэтому правильнее использовать мощный GPU. Кроме того, Smart Traffic System — решение комплексное, одновременно удовлетворяет несколько потребностей заказчика, поэтому и работает несколько иначе.
Проблема
Nomeroff-net запускался на Jetson TX2 и потреблял слишком много ресурсов оперативной памяти из-за чего происходили проблемы с работой других модулей. Библиотека требовала большого количества времени на запуск и inference (вычисление символов с номерного знака). Это связано с тем, что библиотека Nomeroff-net содержит 4 этапа работы при чтении номерного знака (поиск рамки номера, предобработка для ровного расположения в кадре, классификация для вычисления страны ГРЗ, чтение символов). В начальном состоянии репозиторий использует PyTorch, однако есть возможность конвертации моделей под TensorRT.
Задача
Сократить время на запуск, inference и устранить перебои других модулей (модуль настройки системы с интерфейсом, модуль детекции и трекинга авто, модуль детекции ДТП) за счет снижения потребляемых ресурсов оперативной памяти.
С чего начали
Изначально, мы пытались найти аналог Nomeroff-net. Выяснилось, что настолько точных opensource-решений не существует.
По итогу, приняли решение найти библиотеку, которая способна детектировать и распознавать символы на изображении, чтобы адаптировать ее под распознавание отечественных ГРЗ.
В результате получилось найти репозиторий, проект из которого направлен на поиск и распознавание символов на изображении. Поиск символов производится по точкам — найденные символы помещаются в четырехугольники, после чего производится распознавание найденных слов.
Дальше как в сказке — чем дальше, тем страшнее
Несколько дней ушло на то, чтобы понять какие версии библиотек необходимы для запуска проекта, так как в репозитории версии указаны некорректно или указаны не для всех библиотек. Некоторые библиотеки пришлось заменить, так как они уже прекратили поддержку. Также трудности возникли с определением версии PyTorch. Для проверки приходилось пробовать разные драйверы видеокарты, так как разные версии PyTorch требовали разную версию CUDA.
После того, как получилось все запустить, необходимо было адаптировать проект под распознавание номеров. Для более правильной работы в проект была добавлена функция поворачивающая найденный текст, чтобы всегда распознавать горизонтальные объекты.
Также необходимо было поработать с библиотекой символов, сократив ее на 98% — нам нужны были только латинские заглавные буквы и арабские цифры.
Кроме этого производилось распознавание всего текста на картинке, а нам нужно распознавать только номерные знаки.
Для обучения необходимо было разобраться со структурой датасета и форматом, в котором нужно подавать данные на обучение.
После этого пришлось переписать скрипт для обучения модели, чтобы он мог работать с нашим датасетом, потому что поправить скрипт обучения оказалось менее трудозатратно, чем изменить весь датасет.
Много времени ушло на переписывание скрипта, так как для его проверки приходилось запускать обучение на несколько эпох.
С этого момента началось обучение.
Правильно обучить модель получилось далеко не с первого раза, приходилось подбирать параметры обучения: размерность изображения, параметры аугментации датасета, выбор функции потерь и оптимизатор.
Обучение модели
Параметры обучения подбирались последовательно: сначала для detection-модели, а после для — OCR.
Для начала определили оптимальный размер кадра для inference — для этого провели полное обучение моделей с разной размерностью.
Благодаря тестам получилось подобрать размеры, при которых точность распознавания оставалась хорошей. Более того, за счет передачи изображения меньшего размера, был получен значительный прирост в скорости.
После этого пришлось искусственно ухудшать качество некоторых изображений из датасета — они были слишком высокого качества для обучения.
Для наибольшей эффективности изображения выбирались случайно, после чего, также в случайном порядке, применялись всевозможные размывающие фильтры, чтобы приблизить обучающие данные к реальным.
Примеры искаженных изображений: блюр; контраст; блюр + сдвиг; контраст + сдвиг.
Также случайным образом производился поворот изображений на разумное количество градусов — ориентировочно от -60 до 60. Помимо этого, у некоторых изображений меняли размер (сжатие/растяжение одной или двух сторон изображения).
Благодаря таким преобразованиям грязные и размытые номера стали распознаваться гораздо лучше.
Примеры грязных и размытых номеров.
По завершению подбора параметров обучения, проходило долгое обучение. Мы хотели достичь результата работы аналогичного Nomeroff-net. Однако, результаты первых тестов превзошли все наши ожидания. Об этом ниже.
При оценке сравнения точности библиотеки Nomeroff-net и нами разработанной библиотеки использовался такой параметр, как корректность распознавания — распознавание символов на номере при различных исходных данных: грязный, размытый, повернутый номер, расстояние от камеры до номера.
Тестирование модели и результаты
В начале проверки проводились на одном видеофайле хорошего качества. Как только точность распознавания нашего решения стала выше, чем у Nomeroff-net, началось тестирование на других видеофайлах. На первый взгляд, отличия были незначительные. Но при дальнейшем детальном сравнении, мы выяснили, что наше решение распознает номера транспортных средств на бОльшем расстоянии, чем Nomeroff-net. Более того, STS.ГРЗ лучше справляется с грязными или смазанными номерами: точность составила ~90%, в то время как Nomeroff-net показал ~75-80% точности на выбранном фрагменте видео (скриншот выше).
В ходе второго тестирования на видеофайле плохого качества (скриншот ниже) удалось выяснить, что Nomeroff-net допускает сравнительно бОльшее количество ошибок при распознавании с дальней дистанции.
Завершив второе тестирование нашего решения по распознаванию номеров на дальней дистанции, мы получили ~60% полного распознавания. Если не учитывать путаницу в регионе (неправильная первая или вторая цифра, или ошибочное добавление третьей цифры в двузначный регион), точность составляет ~75% (у Nomeroff-net — только в ~30% случаев номера распознаются полностью и в ~40% — без учета ошибок в регионе). Ниже приведена сравнительная таблица точности. Стоит учитывать, что такая большая ошибка вызвана сложным ракурсом, так как номера в кадре видно плохо, а также временем года, в которое большое количество номеров загрязнено.
Параметр/Устройство | STS.ГРЗ | Nomeroff-net |
Точность распознавания | ||
Ошибка в регионе | 47 | 21 |
Ошибка в букве/цифре | 15 | 23 |
Ошибка и в букве, и в цифре | 13 | 73 |
Количество корректно распознанных номеров | 100 | 52 |
Количество нераспознанных номеров | 12 | 11 |
Первичные тесты показали, что наше решение справляется с распознаванием этих номерных знаков почти в 2 раза точнее, чем Nomeroff-net.
Распознавание номеров квадратной формы пока отсутствует, так как в свободном доступе не получилось найти датасет плашек российских номерных знаков квадратной формы. Распознавание номеров спецтехники активно не проверялось.
Как только мы поняли, что точность превысила Nomeroff-net, начали попытки портировать решение под Jetson. Тут тоже не обошлось без сложностей: обученные модели были в TensorFlow формате, а для Jetson нужны TensorRT (как рекомендует производитель Nvidia). Чтобы получить TensorRT необходима ONNX-модель. В итоге, пришлось написать скрипт для конвертации моделей из TensorFlow в ONNX, так как в открытом доступе рабочих скриптов конвертации найти не получилось. С конвертацией из ONNX в TensorRT проблем не возникло: в официальных примерах Nvidia был представлен пример скрипта.
А дальше-то что?
По итогу, в нашем арсенале есть решение, работающее на TensorRT.
Мы смогли написать скрипт, который способен собирать engine-файлы для работы с использованием TensorRT. На данный момент проводятся работы по переводу проекта с TensorFlow на PyTorch. Также планируется переписать проект под последнюю версию PyTorch, чтобы иметь возможность запуска с использованием актуальных драйверов Nvidia (в проекте сейчас используется 12 версия PyTorch, работающая с 11 CUDA).
Параметр/Устройство | STS.ГРЗ | Nomeroff-net |
Потребление ресурсов | ||
ПК: видеопамять | 300-400 MB | 1.5 GB |
ПК: оперативная память | 500-700 MB | 2 GB |
Дисковое пространство | 352 MB | 1,63 GB |
Jetson: оперативная память + видеопамять | 1 GB | 1.1-1.2 GB |
Во время тестов на ноутбуке было обнаружено, что STS.ГРЗ в среднем стал потреблять кратно меньше ресурсов, по сравнению с Nomeroff-net.На ПК 300-400 MB видеопамяти против 1.5 GB и 500-700 MB оперативной памяти против 2 GB. На Jetson прирост производительности оказался не таким впечатляющим — потребление ресурсов уменьшилось в среднем на 15%.
Также получилось создать модели STS.ГРЗ, преобразуемые как под Jetson, так и под Rockchip. Для запуска проекта на Rockchip пришлось изменить несколько слоев обеих моделей. Конвертер моделей Rockchip не может преобразовывать negative слои, поэтому пришлось от них избавиться. Из-за этого изменения пришлось переобучить обе модели, так как после внесения изменений работать они стали некорректно.. Кроме этого, оказалось необходимым переписать скрипты для обучения.
В результате преобразований слоёв, получилось увеличить максимальное расстояние, на котором может распознаваться номер ТС.
К чему пришли?
По итогам работы с проектом STS.ГРЗ, был создан аналогичный Nomeroff-net распознаватель номеров. Однако, в связи с тем, что наши модели совсем не обучались для работы с квадратными плашками номерных знаков, мы оставили вариант использования обеих библиотек.
Также, на момент публикации статьи, мы продолжаем обучать нейросеть распознавать ГРЗ спецтехники, прицепов и иных ТС. В остальном же решение превысило точность распознавания Nomeroff-net с кратно меньшим потреблением ресурсов.
Основные трудности при работе с STS.ГРЗ заключались в том, что нигде не были указаны версии Python библиотек, видеодрайвера, CUDA, Tensorrt и C++ компиляторов.
Без всего этого не получалось запустить изначальный проект, чтобы понять как он работает и видоизменить под наши задачи.
Хоть проект изначально и оказался нерабочим, однако был выбран из-за наличия примеров моделей. Все остальные репозитории, в которых были упоминания моделей, ссылались на Baidu, из которого не было возможности скачать их без аккаунта, а для регистрации аккаунта требуется Китайская сим-карта.
Какие еще сложности удалось преодолеть?
На данный момент активно проводится тестирование нашего распознавателя номеров — STS.ГРЗ. Мы научились собирать это решение в deb-пакет с дальнейшим развертыванием. Со сборкой были сложности, в связи с разной версионностью библиотек TensorRT, установленных на ПК и Jetson. Некоторые методы пришлось переписать отдельно для Jetson (сборка engine файлов и инициализация моделей).
При совместной работе «детектора» и «распознавателя» номеров тоже возникли вопросы. При ручном тестировании ребята не сильно задумывались какие изображения передавать для проверки распознавателя. Логика была такой: если человеческий глаз может разглядеть очертания символов на номерном знаке, значит и программа сможет. Но как это автоматизировать?
Сейчас мы остановились на следующем решении.
При появлении в кадре нового автомобиля, номерной знак которого мы способны распознать, начинается запись кадров, на которых есть этот автомобиль.
Чтобы не проверять сразу по всем кадрам, берем из всех кадров по одному через равные промежутки времени.
В итоге у нас получается около 6-ти кадров, на которых запечатлен автомобиль с момента попадания в поле зрения камеры и заканчивая его выездом. Этот вариант работает довольно эффективно: как минимум с 2-3 кадров символы с номерного знака распознаются корректно.
Планируется также проверить вариант, при котором мы опираемся на размер номерного знака в полученном кадре. Однако, при таком подходе могут возникнуть такие проблемы, как полная потеря автомобиля, при диагональной направленности камеры, относительно номерного знака, так как кадры будут взяты примерно из одного временного промежутка.
Перспективы развития
Добавить распознавание квадратных плашек номерных знаков.
На данный момент наше решение не может распознавать номерные знаки квадратной формы. Связано это с тем, что в нашем датасете полностью отсутствуют такие номерные знаки. В связи с этим, попыток по распознаванию таких номеров не предпринималось. Для добавления такой возможности необходимо расширить наш датасет фотографиями автомобилей с подходящими номерами.
Оптимизировать работу STS.ГРЗ на Jetson.
На ноутбуке производительность возросла в 2 раза при переходе с Nomeroff-net на наше собственное решение. С Jetson так не получилось, нагрузка опустилась всего на 15-20%. Планируется попробовать оптимизировать работу сервиса, распараллелить препроцессинг и постпроцессинг изображений.
На момент публикации статьи, в системе распознавания номеров продукта STS, изображения отправляются на распознавание по одному, что замедляет работу системы, так как нам необходимо дождаться ответа от STS.ГРЗ по каждому отправленному изображению. Решили провести тестирование работы с возможностью обработки сразу нескольких изображений — Batch. Уже успели провести несколько предварительных тестов и получили прирост скорости обработки изображений порядка 30%. На очереди — тестирование стабильности и нагрузочное тестирование.