Представляю вам образовательный проект — “Нейросетевой идентификатор объектов” разработанный в рамках учебно-методического комплекса на базе одноплатного компьютера Repka PI 4.
В последние годы задачи компьютерного зрения и, в частности, детекция объектов, стали неотъемлемой частью многих проектов — от систем видеонаблюдения до умных гаджетов и роботов. Однако для встраиваемых и маломощных устройств критически важна не только точность, но и скорость работы моделей. В этой статье расскажу о проекте “Нейросетевой идентификатор объектов” — компактной Python-реализации детектора объектов на базе модели YOLOFastestV2 с использованием высокопроизводительного inference-фреймворка NCNN. Проект позволяет в реальном времени распознавать объекты с обычной USB-камеры и легко интегрируется в другие Python-проекты.
Проект будет собираться с использованием “Учебно-методический комплекс REPKA”. Схему сборки можно найти в разделе "Примеры готовых проектов" учебного пособия УМК “REPKA”.
Также все необходимые материалы и схемы подключения доступны в репозитории на платформе Gitflic.
Кратко о технологиях
-
YOLOFastestV2 — одна из самых быстрых и компактных моделей для детекции объектов, ориентированная на работу на edge-устройствах.
-
NCNN — легковесный и быстрый фреймворк для инференса нейросетей, разработанный Tencent, с поддержкой Python через bindings.
-
OpenCV — для захвата видео с камеры, визуализации и работы с изображениями.
Архитектура и структура проекта
Проект организован следующим образом:
ml-repka/
├── docs # Документация данного проекта
├── py
│ ├── yolofastestv2.py # Основной класс детектора
│ ├── main.py # Пример запуска с камерой
│ ├── led_controller.py # Управление RGB лентой
│ └── data/ # Веса и параметры модели
│ ├── yolo-fastestv2-opt.param
│ └── yolo-fastestv2-opt.bin
└── Makefile # Набор инструкций для запуска и установки зависимостей
yolofastestv2.py — здесь реализован класс YoloFastestV2, который инкапсулирует всю логику загрузки модели, препроцессинга, инференса и постобработки (NMS, декодирование выходов).
main.py — пример использования: захват видео с камеры, обработка каждого кадра, отрисовка рамок и подписей, вывод списка обнаруженных объектов в отдельной панели.
led_controller.py — реализует управление светодиодами (например, WS2812, которые управляются через SPI) с использованием библиотеки spidev
. Код генерирует уникальные цвета для светодиодов и отправляет эти цвета на ленту через SPI.
Для разработки кода будет использоваться текстовый редактор Geany, который входит в состав стандартного ПО Репка ОС.
Использование OpenCV в задачах компьютерного зрения
В нашем проекте для задач компьютерного зрения и работы с изображениями мы выбрали библиотеку OpenCV. Давайте разберёмся, почему именно этот инструмент оказался оптимальным, и какие существуют альтернативы.
OpenCV — это одна из самых мощных и популярных библиотек для обработки изображений и видео. Она поддерживает практически все базовые и продвинутые операции: чтение/запись файлов, преобразования, фильтрация, работа с цветами, геометрические преобразования, детекция объектов, трекинг, распознавание лиц и многое другое.
Она появилась одной из первых и за годы стала стандартом в мире компьютерного зрения. С помощью OpenCV можно делать практически всё: от простого чтения и сохранения изображений до сложных операций вроде фильтрации, преобразования, распознавания объектов, работы с видео и даже интеграции с нейросетями. В нашем случае OpenCV позволяет легко получать кадры с камеры, обрабатывать их, рисовать рамки вокруг найденных объектов, выводить текст и визуализировать результаты прямо в реальном времени. Всё это делается буквально несколькими строками кода, и не требует глубоких знаний о низкоуровневой обработке изображений.
Конечно, OpenCV — не единственный вариант. Для простых задач, например, если нужно просто открыть картинку, изменить размер или наложить фильтр, можно использовать Pillow (PIL) — она проще и легче, но не умеет работать с видео и не поддерживает сложные алгоритмы. Для научных экспериментов и обработки изображений часто используют scikit-image — там много интересных фильтров и методов, но она медленнее и не такая универсальная. Есть ещё dlib — она хорошо подходит для распознавания лиц, но не для общего компьютерного зрения. Для вывода изображений на экран иногда используют matplotlib, но это скорее инструмент для визуализации, а не для обработки.
В целом, если задача комплексная и связана с обработкой видео, детекцией объектов, визуализацией и интеграцией с нейросетями, OpenCV остаётся самым удобным и мощным инструментом. Именно поэтому мы выбрали его для нашего проекта.поддерживает работу с видео и сложные алгоритмы компьютерного зрения.
Использование NCNN для взаимодействия с нейронными сетями
Мы выбрали NCNN для взаимодействия с нейронной сетью, потому что этот фреймворк идеально сочетает в себе лёгкость, высокую производительность и простоту интеграции. NCNN специально разработан для быстрого инференса на устройствах с ограниченными ресурсами — таких как одноплатные компьютеры, мобильные телефоны и встраиваемые системы. Благодаря минимальным внешним зависимостям и отличной оптимизации, NCNN позволяет запускать современные нейросетевые модели даже там, где другие решения оказываются слишком "тяжёлыми" или медленными.
В нашем коде мы используем базовые, но очень важные возможности API NCNN. Прежде всего, это создание и настройка объекта сети ncnn.Net():
self.net = ncnn.Net()
self.net.opt.use_vulkan_compute = self.use_gpu # Включить ли ускорение на видеокарте (если есть поддержка Vulkan)
self.net.opt.num_threads = self.num_threads # Сколько потоков (ядер процессора) использовать для вычислений
self.net.opt.use_winograd_convolution = True # Использовать ли оптимизацию Winograd для ускорения свёрток (быстрее работает на некоторых процессорах)
self.net.opt.use_sgemm_convolution = True # Использовать ли оптимизацию SGEMM для ускорения матричных операций (ускоряет работу на CPU)
self.net.opt.use_int8_inference = True # Включить ли ускоренный режим работы с 8-битными числами (int8), чтобы сеть работала быстрее и меньше ела памяти
self.net.opt.use_fp16_packed = True # Использовать ли упаковку данных в 16-битные блоки (FP16), чтобы ускорить вычисления и сэкономить память
self.net.opt.use_fp16_storage = True # Хранить ли данные в 16-битном формате (FP16), чтобы экономить память
self.net.opt.use_fp16_arithmetic = True # Считать ли все вычисления в 16-битном формате (FP16), чтобы ускорить работу (может быть чуть менее точно)
self.net.opt.use_int8_storage = False # Не использовать хранение данных в 8-битном формате (int8)
self.net.opt.use_int8_arithmetic = True # Использовать ли вычисления в 8-битном формате (int8)
self.net.opt.use_packing_layout = True # Использовать ли специальную упаковку данных для ускорения работы на некоторых устройствах
self.net.opt.use_shader_pack8 = False # Не использовать особый режим ускорения для видеокарт (shader pack8)
Загрузка параметров и весов модели с помощью методов load_param()
и load_model():
param_path = os.path.join(self.model_dir, "yolo-fastestv2-opt.param")
bin_path = os.path.join(self.model_dir, "yolo-fastestv2-opt.bin")
self.net.load_param(param_path) # Загружаем структуру сети
self.net.load_model(bin_path) # Загружаем веса сети
После этого мы создаём экстрактор create_extractor()
, который позволяет выполнить инференс — то есть прогнать изображение через нейросеть и получить результат:
ex = self.net.create_extractor()
Для передачи изображения на вход сети используется метод input():
ex.input("input.1", mat_in) # Передаем изображение на вход сети
А для получения выходных данных — метод extract():
# Запрашиваем у сети два выходных слоя (они нужны для поиска объектов разного размера)
out_names = ["794", "796"]
# Получаем закодированные коэффициенты для рамок и вероятностей
outs = [ex.extract(name)[1] for name in out_names]
Также мы используем класс ncnn.Mat
для преобразования и нормализации входных изображений, что необходимо для корректной работы модели:
# Преобразуем изображение к нужному размеру и нормализуем цвета
mat_in = ncnn.Mat.from_pixels_resize(
img, ncnn.Mat.PixelType.PIXEL_BGR, img_w, img_h, self.input_size, self.input_size
)
Кроме этих базовых методов, в NCNN есть и другие популярные возможности, которые часто используют в более сложных проектах. Например, можно управлять вычислениями на GPU с помощью Vulkan, что позволяет значительно ускорить инференс на поддерживаемых устройствах. Для этого в объекте сети можно включить опцию use_vulkan_compute
. Также NCNN поддерживает работу с потоками (многопоточность), что позволяет задействовать несколько ядер процессора для ускорения обработки — это настраивается через параметр num_threads
.
Ещё одна интересная возможность — это поддержка различных оптимизаций, таких как Winograd и SGEMM для ускорения свёрточных и матричных операций, а также использование 8-битных и 16-битных вычислений (int8, fp16), что позволяет экономить память и ускорять работу на некоторых устройствах.
В более продвинутых сценариях можно использовать NCNN для работы с кастомными слоями, подключать свои плагины, а также использовать инструменты для конвертации моделей из других фреймворков (например, из PyTorch, TensorFlow, ONNX) в формат NCNN.
Почему YOLOFastestV2?
YOLOFastestV2 — это облегчённая версия семейства моделей YOLO (You Only Look Once), специально разработанная для работы на устройствах с ограниченными вычислительными ресурсами: одноплатных компьютерах, мобильных устройствах, встраиваемых системах. Главная особенность этой модели — высокая скорость работы при приемлемой точности. Она способна обрабатывать видео в реальном времени даже на слабых процессорах, что критично для задач, где важна минимальная задержка и нет возможности использовать мощные видеокарты.
Для нас важным фактором стало то, что YOLOFastestV2 легко интегрируется с такими фреймворками, как NCNN, и отлично работает в связке с OpenCV. Это позволяет строить компактные, быстрые и надёжные решения, которые можно запускать практически на любом оборудовании.
Какие есть альтернативы?
Существует множество других моделей для детекции объектов, каждая из которых имеет свои плюсы и минусы:
- YOLOv3, YOLOv4, YOLOv5, YOLOv8
Это более "тяжёлые" и точные версии YOLO. Они обеспечивают высокую точность, но требуют больше вычислительных ресурсов и памяти. Подходят для серверов и мощных ПК, но не для мобильных устройств.
- YOLO-Nano, YOLO-Lite, Tiny-YOLO
Это облегчённые версии YOLO, похожие по идеологии на YOLOFastestV2. Они тоже рассчитаны на работу в реальном времени на слабом железе, но по скорости и компактности часто уступают YOLOFastestV2.
- MobileNet-SSD, SSDLite
Модели на основе MobileNet и Single Shot Detector (SSD) также популярны для мобильных и встраиваемых решений. Они хорошо сбалансированы по скорости и точности, но обычно проигрывают YOLOFastestV2 по скорости на очень слабых устройствах.
- EfficientDet-Lite
Современная серия моделей, оптимизированных для мобильных устройств. EfficientDet-Lite может показывать отличные результаты по точности, но требует больше памяти и ресурсов, чем YOLOFastestV2.
- PP-YOLO, CenterNet, RetinaNet
Это более современные и точные модели, но они гораздо тяжелее и медленнее, чем YOLOFastestV2, и не предназначены для real-time на слабых устройствах.
Когда стоит выбрать альтернативу?
Если у вас нет ограничений по ресурсам и критична максимальная точность — лучше использовать старшие версии YOLO (например, YOLOv5/v8) или EfficientDet. Если задача — мобильное приложение или встраиваемое устройство, где важна скорость и компактность, то оптимальным выбором будут YOLOFastestV2, Tiny-YOLO или MobileNet-SSD.
Вывод
YOLOFastestV2 — это идеальный компромисс между скоростью, точностью и простотой интеграции для задач, где важна работа в реальном времени на недорогом или маломощном оборудовании. Именно поэтому мы выбрали эту модель для нашего проекта. Она позволяет быстро и эффективно решать задачи детекции объектов, не требуя дорогого "железа" и сложной настройки. Альтернативы существуют, и выбор всегда зависит от конкретных требований к скорости, точности и доступным ресурсам.
Как это работает
1. Загрузка модели
При инициализации YoloFastestV2 загружает веса и параметры модели из директории data/ с помощью NCNN.
2. Обработка кадра
Каждый кадр с камеры приводится к нужному размеру, нормализуется и подается на вход модели.
3. Детекция и постобработка
Модель возвращает bounding box'ы, вероятности и классы объектов. Далее применяется Non-Maximum Suppression (NMS) для устранения пересечений.
4. Визуализация
Для каждого объекта рисуется яркая рамка и подпись с классом и вероятностью. Справа появляется полупрозрачная панель со списком всех объектов в кадре.
5. Визуализация объектов на RGB ленте
Если у вас имеется адресная RGB лента, количество объектов в кадре будет отображаться с помощью соответствующего числа светодиодов.
Подготовительный этап #
1. Подключим дополнительное питание 5V к макетной плате:
2. После чего выведем дополнительное питание на макетную плату:
3. Подключим переходник с шлейфа на макетную плату:
4. Соединим шлейф с переходником для подключения к макетной плате и Repka Pi 4:
5. Итоговый результат должен выглядеть таким образом:
Сборка проекта
1. Необходимо подключить USB камеру к Repka Pi 4.
2. Согласно схемам 7 и 8 подключить светодиодную ленту, в нашем случае ws2812b, к макетной плате.
Вместо светодиодной ленты можно использовать различные исполнительные устройства, такие как мотор, сервоприводы, зуммер и тд.
2.1. Подключение адресной светодиодной ленты (WS2812b).
Как видно из рисунков 7 и 8 устройство подключается к MOSI через резистор 100 Ом и питается от 5V.
2.2. Выполним подключение согласно таблице 1.
Макетная плата | WS2812b |
5V | 5V |
GND | GND |
MOSI | MOSI |
Таблица 1. Подключение WS2812b к макетной плате.
Вы можете собрать более бюджетную версию данного проекта.
Для более бюджетной реализации проекта можно обойтись без активного охлаждения, используя Repka Pi 4 в стандартной комплектации, а также макетную плату без внешнего источника питания — при этом остальные компоненты остаются неизменными.
Для подключения нам потребуется “Распиновка портов на 40 pin разъёме на Repka Pi 4“, см. изображение ниже.
Поскольку расширительная плата GPIO полностью повторяет конфигурацию распиновки, можно применить те же таблицы и схемы, которые использовались ранее для устройств:
3. Выполним подключение WS2812b согласно таблице 1:
Питание устройств также можно осуществлять с использованием:
Внимание! Подаваемое напряжение не должно превышать 5 В.
А. Лабораторного блока питания:
Б. Аккумуляторного блока питания:
Запуск проекта
1. Клонируем репозиторий:
git clone git@gitflic.ru:repka_pi/repka-pi_iot-examples.git
2. Переходим в директорию:
cd repka-pi_iot-examples/
3. Установим зависимости для проекта, процесс занимает от 15 до 30 минут:
make setup-ml-repka
4. Выполните команду ниже. Если аргумент CAMERA не указан, по умолчанию будет использоваться камера с ID равным 0. Если не задан параметр RGB, его значение будет установлено в false. В случае подключения светодиодной ленты укажите RGB=true.
make ml-repka CAMERA=<ID камеры> RBG=<Режим работы RGB (true/false)>
После запуска появится окно, после чего можете начать идентификацию объектов.
Как уже упоминалось, количество светодиодов на адресной RGB ленте будет соответствовать количеству объектов в кадре.
Практическая значимость
Проект “Нейросетевой идентификатор объектов” обладает высокой практической значимостью как в образовательной, так и в прикладной сфере. Благодаря использованию компактной и производительной модели YOLOFastestV2 на базе фреймворка NCNN, проект демонстрирует, как реализовать полноценную систему компьютерного зрения на Repka PI 4. Это делает его отличной демонстрационной и учебной платформой для студентов, преподавателей и начинающих разработчиков, осваивающих современные методы обработки изображений и нейросетевого инференса.
С практической точки зрения проект может быть легко адаптирован под различные задачи: интеллектуальное видеонаблюдение, системы безопасности, сортировка объектов, робототехника и автоматизация. Реализация в реальном времени делает его особенно полезным в сценариях, где критична скорость реакции системы. При этом весь стек технологий открыт и написан на Python, что позволяет свободно модифицировать и расширять проект под конкретные нужды.
Расширение проекта
Проект обладает широкими возможностями для дальнейшего расширения и модификации. В первую очередь, можно добавить поддержку дополнительных моделей нейросетей — например, облегчённые версии YOLOv5 или MobileNet-SSD, чтобы сравнить точность и производительность на платформе Repka PI 4. Также возможна интеграция с другими сенсорами: например, использование GPS-модуля для геометок, акселерометра для отслеживания движения устройства или BME280 для учета погодных условий при детекции объектов на улице.
Другим направлением развития может стать реализация пользовательского интерфейса на базе веб-технологий или PyQt, что упростит управление системой и визуализацию результатов. Также возможно расширение функциональности за счёт записи логов, ведения статистики по распознанным объектам и сохранения фрагментов видео при срабатывании на определённые классы объектов.
При желании проект может быть интегрирован в более крупную IoT-систему с облачным хранилищем или управлением через мобильное приложение, что открывает перспективы для создания коммерчески применимых решений на базе доступных отечественных одноплатных компьютеров.
Видеообзор проекта
Для более детального ознакомления с проектом, вы можете посмотреть видеообзор на платформе Rutube.
Пример использования с Python
Проект полностью реализован на языке Python. Код для работы с нейросетевым идентификатором объектов можно найти в репозитории на платформе Gitflic.
На данную тему опубликована еще одна статья в блоге.