Сегодня обработка изображений прочно вошла в нашу жизнь. Никого не удивляет распознавание лиц или дорожной разметки. Самой распространенной библиотекой для этих целей на данный момент является OpenCV. На сегодняшний день OpenCV ориентирован прежде всего на большие платформы. И хотя старшие модели современных микроконтроллеров обладают ресурсами сопоставимыми с Pentium II, запуск на них OpenCV все еще является очень редким, даже экзотическим явлением.
Какое-то время назад мы показали, что существует принципиальная возможность использовать OpenCV на STM32 (и других микроконтроллерах подобного класса). Тогда нашей целью было продемонстрировать возможность использования данной библиотеки на подобных аппаратных платформах. Поэтому, хотя мы и получили очень низкую производительность, мы не стали разбираться в ее причинах. На текущий момент мы исправили очевидные недостатки первого решения, что позволило добиться приемлемой производительности. В данной статье приведены результаты замеров производительности для различных примеров использования OpenCV на платформе STM32F7.
Все примеры приведенные в статье выполнены на основе Embox и могут быть воспроизведены самостоятельно, следуя инструкции из репозитория с примерами. Также мы использовали для наших примеров на плате флаг оптимизации -Os. Во всех примерах используется включенный кеш. Изображения могут располагаться на SD-карте. В примерах мы храним изображения в QSPI флеш, которая есть на демонстрационной плате, для более простой базовой инструкции при воспроизведении результатов.
Начнем с того же самого примера, который был использован в предыдущей работе, а именно определение границ. В примере используется алгоритм Кэнни.
Мы приведем лог вывода при запуске приложения edges на Embox, что позволит сравнить улучшение производительности по сравнению с нашей предыдущей работой. Для остальных приложений мы будем приводить только таблицы с результатами измерений.
Пример анализируемого изображения:
Вывод для изображения 512x269
Вывод для изображения 512x480
Результаты
Данный пример из состава OpenCV в результате своей работы должен определить кластеры точек и обвести каждый из них окружностью соответствующего цвета.
Для оценки плотности их распределения в OpenCV используется понятие “компактность”:
Иными словами, compactness — это показатель того насколько близко точки сосредоточены к центру кластера.
В качестве входных данных kmeans.cpp генерирует картинку размером 480 x 480 c несколькими кластерами точек разных цветов. Центр каждого такого кластера выбирается случайным образом, а точки в кластер добавляются в соответствии с нормальным распределением.
Распознавание геометрический фигур, в частности прямоугольников, также является стандартным примером в составе библиотеки OpenCV.
Пример анализируемого изображения:
Результаты для изображений 400x300:
Распознавание лиц было изначальной целью нашего исследования. Мы хотели оценить насколько подобные алгоритмы хорошо работают на аналогичных платах. Используем стандартный пример facedetect с набором из пяти изображений. В примерах используется Haar-cascade Detection (https://docs.opencv.org/4.5.2/db/d28/tutorial_cascade_classifier.html )
Пример анализируемого изображения:
Для изображений 256x256:
Для изображений 480x480:
Повышая сложность мы решили попробовать как работает определение людей на изображении. Для этого можно использовать пример peopledetect.
Пример изображение:
Результаты
QR коды является широко используемым примером распознавания образов.
Пример изображения взятый случайным образом из интернета:
Результаты
Данный пример не уместился во внутреннюю память, поэтому приведены результаты только из QSPI
Есть несколько примечательных моментов, которые мы обнаружили при работе с OpenCV на микроконтроллерах. Первый, код из внутренней памяти работает быстрее чем из внешней QSPI flash, даже при включенном кэше.
Второй, на наш взгляд, также связанные с кэшем, это зависимость производительности от размещения кода. Мы обнаружили, что незначительное изменение кода, например, добавление команды, которая не вызывается в основном алгоритме, может увеличить или уменьшить производительность на 5 или даже более процентов.
Третий, достаточно ограниченный объем внутренней памяти (2 MB). Нам не удалось быстро запустить пример с распознаванием QR кодов из внутренней памяти.
Еще одна важная особенность относится к ядрам ARM Cortex-M. Мы использовали ядра с поддержкой SIMD инструкций. Данная технология помогает увеличить производительность путем обработки нескольких арифметических команд на одном регистре. Для оценки того что это помогает для наших задач мы провели замеры на Linux c поддержкой SIMD инструкций и без и выяснили, что на некоторых примерах использование SIMD дает прирост производительности на 80 %.
Однако для нашего процессора, gcc не умеет автоматически генерить код с использованием SIMD инструкций. Существует поддержка только в виде Intrinsic functions. Иными словами нужно вставлять эти команды в ручном режиме. OpenCV поддерживает такой подход. Можно реализовать поддержку SIMD для специальной архитектуры. Но на текущий момент OpenCV рассчитан только на работу с длинными типами данных (128 бит и больше). Поэтому в рамках данной работы не было оценено улучшение производительности при использовании SIMD на STM32. Мы надеемся это будет направление будущих исследований.
Приведенные результаты говорят о том, что на микроконтроллерах можно использовать такое сложное программное обеспечение как OpenCV. Запущен целый ряд примеров и все успешно работали. Однако, производительность заметно ниже чем у хостовых платформ.
Применение OpenCV на микроконтроллерах сильно зависит от задач, которые необходимо решить. Большинство базовых алгоритмов работают незаметно глазу. Тот же алгоритм выявления границ отрабатывал за доли секунды, такой производительности может быть вполне достаточно для автономного робота. Комплексные алгоритмы, например, обработка QR кода могут быть использованы, но необходимо оценивать плюсы и минусы решения. С одной стороны 3 секунды это много для распознавания, а с другой, для некоторых целей может быть достаточно.
Поэтому предположу, что для распознавания сложных объектов, например, выявления человека, подобные платформы, еще недостаточно мощные. Задержка сильно заметна по сравнению с распознаванием той же картинки на хосте. Но нужно учитывать и то что сравнивалось с 64 битным intel-i7 c 8 ядрами и принципиально другой частотой, а, следовательно, и потребление у данной платформы совсем другое. И к тому же в сравнении участвовал не самый мощный микроконтроллер. Даже у STM32 есть серия H7, которая в два раза мощнее.
Результаты можно увидеть на видео
Вы можете воспроизвести результаты полученные в статье. Для этого понадобятся два репозитория. Основной репозиторий Embox и репозиторий с примерами изображений и готовыми конфигурациями для платы STM32F769i-discovery. Следуя инструкциям в README файле из репозитория и примерами вы можете воспроизвести результаты.
Вы можете также использовать другие платы, для этого вам необходимо собрать требуемую конфигурацию. Кроме того, вы можете поэкспериментировать с другими изображениями или разместить изображения на SD-карте, что также требует только изменения конфигурации Embox.
P. S. Впервые данныя статья была опубликована на английском языке на сайте emedded.com
Какое-то время назад мы показали, что существует принципиальная возможность использовать OpenCV на STM32 (и других микроконтроллерах подобного класса). Тогда нашей целью было продемонстрировать возможность использования данной библиотеки на подобных аппаратных платформах. Поэтому, хотя мы и получили очень низкую производительность, мы не стали разбираться в ее причинах. На текущий момент мы исправили очевидные недостатки первого решения, что позволило добиться приемлемой производительности. В данной статье приведены результаты замеров производительности для различных примеров использования OpenCV на платформе STM32F7.
Все примеры приведенные в статье выполнены на основе Embox и могут быть воспроизведены самостоятельно, следуя инструкции из репозитория с примерами. Также мы использовали для наших примеров на плате флаг оптимизации -Os. Во всех примерах используется включенный кеш. Изображения могут располагаться на SD-карте. В примерах мы храним изображения в QSPI флеш, которая есть на демонстрационной плате, для более простой базовой инструкции при воспроизведении результатов.
Edge detection
Начнем с того же самого примера, который был использован в предыдущей работе, а именно определение границ. В примере используется алгоритм Кэнни.
Мы приведем лог вывода при запуске приложения edges на Embox, что позволит сравнить улучшение производительности по сравнению с нашей предыдущей работой. Для остальных приложений мы будем приводить только таблицы с результатами измерений.
Пример анализируемого изображения:
Вывод для изображения 512x269
root@embox:(null)#edges fruits.png 20
Image: 512x269; Threshold=20
Detection time: 0 s 116 ms
Framebuffer: 800x480 32bpp
Вывод для изображения 512x480
root@embox:(null)#edges fruits.png 20
Image: 512x480; Threshold=20
Detection time: 0 s 254 ms
Framebuffer: 800x480 32bpp
Результаты
Image | time from ROM (ms) | time from QSPI (ms) |
---|---|---|
fruits.png 512x269 | 116 | 120 |
fruits.png 512x480 | 254 | 260 |
K-means
Данный пример из состава OpenCV в результате своей работы должен определить кластеры точек и обвести каждый из них окружностью соответствующего цвета.
Для оценки плотности их распределения в OpenCV используется понятие “компактность”:
compactness: It is the sum of squared distance from each point to their corresponding centers.
Иными словами, compactness — это показатель того насколько близко точки сосредоточены к центру кластера.
В качестве входных данных kmeans.cpp генерирует картинку размером 480 x 480 c несколькими кластерами точек разных цветов. Центр каждого такого кластера выбирается случайным образом, а точки в кластер добавляются в соответствии с нормальным распределением.
Compactness | time from ROM (ms) | time from QSPI (ms) |
---|---|---|
733589 | 34 | 98 |
160406 | 6 | 18 |
331447 | 14 | 38 |
706280 | 13 | 36 |
399182 | 8 | 25 |
Squares
Распознавание геометрический фигур, в частности прямоугольников, также является стандартным примером в составе библиотеки OpenCV.
Пример анализируемого изображения:
Результаты для изображений 400x300:
Image | time from ROM (ms) | time from QSPI (ms) |
---|---|---|
pic1.png | 1312 | 1668 |
pic2.png | 4893 | 7268 |
pic3.png | 1263 | 1571 |
pic4.png | 2351 | 3590 |
pic5.png | 1235 | 1515 |
pic6.png | 1575 | 2202 |
Facedetect
Распознавание лиц было изначальной целью нашего исследования. Мы хотели оценить насколько подобные алгоритмы хорошо работают на аналогичных платах. Используем стандартный пример facedetect с набором из пяти изображений. В примерах используется Haar-cascade Detection (https://docs.opencv.org/4.5.2/db/d28/tutorial_cascade_classifier.html )
Пример анализируемого изображения:
Для изображений 256x256:
Image | time from ROM (ms) | time from QSPI (ms) |
---|---|---|
seq_256x256/img_000.png | 3389 | 3801 |
seq_256x256/img_001.png | 4015 | 4454 |
seq_256x256/img_002.png | 4016 | 4464 |
seq_256x256/img_003.png | 3315 | 3717 |
seq_256x256/img_004.png | 3526 | 3952 |
Для изображений 480x480:
Image | time from ROM (ms) | time from QSPI (ms) |
---|---|---|
seq_256x256/img_000.png | 14406 | 16149 |
seq_480x480/img_001.png | 14784 | 16578 |
seq_480x480/img_002.png | 15106 | 16904 |
seq_480x480/img_003.png | 12695 | 14352 |
seq_480x480/img_004.png | 14655 | 16446 |
Peopledetect
Повышая сложность мы решили попробовать как работает определение людей на изображении. Для этого можно использовать пример peopledetect.
Пример изображение:
Результаты
Image | time from ROM (ms) | time from QSPI (ms) |
---|---|---|
basketball2.png 640x480 | 40347 | 52587 |
QR code
QR коды является широко используемым примером распознавания образов.
Пример изображения взятый случайным образом из интернета:
Результаты
Данный пример не уместился во внутреннюю память, поэтому приведены результаты только из QSPI
Image | time from ROM (ms) | time from QSPI (ms) |
---|---|---|
qrcode_600x442.png | — | 3092 |
Особенности работы на микроконтроллерах
Есть несколько примечательных моментов, которые мы обнаружили при работе с OpenCV на микроконтроллерах. Первый, код из внутренней памяти работает быстрее чем из внешней QSPI flash, даже при включенном кэше.
Второй, на наш взгляд, также связанные с кэшем, это зависимость производительности от размещения кода. Мы обнаружили, что незначительное изменение кода, например, добавление команды, которая не вызывается в основном алгоритме, может увеличить или уменьшить производительность на 5 или даже более процентов.
Третий, достаточно ограниченный объем внутренней памяти (2 MB). Нам не удалось быстро запустить пример с распознаванием QR кодов из внутренней памяти.
Еще одна важная особенность относится к ядрам ARM Cortex-M. Мы использовали ядра с поддержкой SIMD инструкций. Данная технология помогает увеличить производительность путем обработки нескольких арифметических команд на одном регистре. Для оценки того что это помогает для наших задач мы провели замеры на Linux c поддержкой SIMD инструкций и без и выяснили, что на некоторых примерах использование SIMD дает прирост производительности на 80 %.
Однако для нашего процессора, gcc не умеет автоматически генерить код с использованием SIMD инструкций. Существует поддержка только в виде Intrinsic functions. Иными словами нужно вставлять эти команды в ручном режиме. OpenCV поддерживает такой подход. Можно реализовать поддержку SIMD для специальной архитектуры. Но на текущий момент OpenCV рассчитан только на работу с длинными типами данных (128 бит и больше). Поэтому в рамках данной работы не было оценено улучшение производительности при использовании SIMD на STM32. Мы надеемся это будет направление будущих исследований.
Анализ результатов
Приведенные результаты говорят о том, что на микроконтроллерах можно использовать такое сложное программное обеспечение как OpenCV. Запущен целый ряд примеров и все успешно работали. Однако, производительность заметно ниже чем у хостовых платформ.
Применение OpenCV на микроконтроллерах сильно зависит от задач, которые необходимо решить. Большинство базовых алгоритмов работают незаметно глазу. Тот же алгоритм выявления границ отрабатывал за доли секунды, такой производительности может быть вполне достаточно для автономного робота. Комплексные алгоритмы, например, обработка QR кода могут быть использованы, но необходимо оценивать плюсы и минусы решения. С одной стороны 3 секунды это много для распознавания, а с другой, для некоторых целей может быть достаточно.
Поэтому предположу, что для распознавания сложных объектов, например, выявления человека, подобные платформы, еще недостаточно мощные. Задержка сильно заметна по сравнению с распознаванием той же картинки на хосте. Но нужно учитывать и то что сравнивалось с 64 битным intel-i7 c 8 ядрами и принципиально другой частотой, а, следовательно, и потребление у данной платформы совсем другое. И к тому же в сравнении участвовал не самый мощный микроконтроллер. Даже у STM32 есть серия H7, которая в два раза мощнее.
Результаты можно увидеть на видео
Воспроизведение результатов
Вы можете воспроизвести результаты полученные в статье. Для этого понадобятся два репозитория. Основной репозиторий Embox и репозиторий с примерами изображений и готовыми конфигурациями для платы STM32F769i-discovery. Следуя инструкциям в README файле из репозитория и примерами вы можете воспроизвести результаты.
Вы можете также использовать другие платы, для этого вам необходимо собрать требуемую конфигурацию. Кроме того, вы можете поэкспериментировать с другими изображениями или разместить изображения на SD-карте, что также требует только изменения конфигурации Embox.
P. S. Впервые данныя статья была опубликована на английском языке на сайте emedded.com