понедельник, 8 мая 2023 г.

ESP32-CAM выделение границ на изображении перекресным оператором Робертса

Одной из задач машинного зрения является отделение одних объектов, на изображении, от других. А одним из путей решения данной задачи может быть например выделение границ путем определения переходов цветов на изображении. Одним из ранних алгоритмов для этого является выделение границ перекресным оператором робертса. Существуют более современные алгоритмы (оператор Собеля, оператор Айверсона и т.д.) но оператор Робертса является простым и быстрым по этому используется поныне и подходит для недорогой платы за 5 долларов. Реализовывать алгоритмы машинного зрения можно проще, используя например javascript библиотеку opencv. Но такой подход работает только если есть связь модуля с компьютером т.к. opencv слишком тяжелая и ресурсозатратная библиотека для модуля ESP32-CAM если нужна автономность (которая может быть важна для автоматизации) то алгоритмы машинного зрения нужно реализовывать на стороне сервера. В данном блоге уже есть статья о том как получить массив пикселей с фотографии модуля ESP32 CAM. (см. датчик цвета на ESP32-CAM -> https://electe.blogspot.com/2022/11/esp32-cam.html). Далее, после того как массив пикселей получен, можно подвергать его воздействию всевозможных алгоритмов с целью их исследования. Массив пикселей содержит 3 байта на каждый пиксель. Один байт для яркости синей составляющей, один для зеленой и один для красной. Именно в таком порядке, как было выяснено ранее, компоненты располагаются в получаемом массиве.

Однако для понимания работы алгоритма порядок не важен. Предположим что каждый пиксель имеет всего одну компоненту яркости т.е. изображение не цветное. В таком случае для определения границы какого либо объекта в какой либо точке на изображении из 4х пикселей можно найти корень из суммы квадратов разностей двух пикселей находящихся на разных диагоналях:
или сумму модулей разностей яркостей пикселей на диагоналях. Будут ли использоваться модули или корень - не важно с точки зрения результата абстрактного алгоритма но для работы на реальном процессоре, вариант с модулями более предпочтителен т.к. его быстродействие будет больше. Суть метода заключается в том что с какой бы стороны на какую не менялся цвет, в этом перекрестии, это изменение будет выражено положительным значением результата вычисления данной формулы. Для того чтобы увидеть границы объектов, на изображении, нужно пройтись данной формулой по всем этим точкам из 4 пискелей со смещением на один пиксель на каждой итерации не затрагивая крайние справа и снизу пиксели всего изображения т.к. они сильно не повлияют на результат какой либо реальной фотографии с не очень низким разрешением. Прелесть этого метода (помимо быстродействия) также заключается в том что результат вычисления можно записывать в ту же самую матрицу из которой берутся яркости пикселей изображения, что не требует дополнительного выделения оперативной памяти чем её экономит. Прежде чем применить данный алгоритм к цветному изображению, можно сначала пройтись по всей матрице и усреднить значение трех компонент яркости каждого пикселя или же пройтись оператором Робертса по каждым компонентам в отдельности. Как будет показано в видео, внизу страницы, на практике визуально результат получается практически одинаковым.

Код скетча можно скопировать из текстового поля:

Данный код является переделкой примера который скачивается вместе с библиотекой для данного модуля для среды Arduino. Код длинный а его полный разбор будет ещё длиннее поэтому лучше сосредоточиться на более интересных вещах. А разбор работы именно с аппаратными возможностями данного модуля, возможно будут выделены в отдельные статьи в данном блоге. Код алгоритма Робертса помещен в функцию capture_handler т.к. она вызывается после того как делается снимок, который можно разобрать на пиксели и обработать данным алгоритмом, после чего отправить результат по WIFI для просмотра на каком либо устройстве типа смартфона. Для того чтобы не было необходимости в роутере для получения результата. Добавлена возможность работы модуля в режиме точки доступа. В переменную ssid нужно записать название WIFI сети которую создаст модуль и к которой нужно будет подключиться для получения результата. В переменную password нужно записать пароль который нужно будет ввести при подключении к WIFI сети которую создаст модуль. IP адрес который нужно будет ввести в адресной строке браузера, после подключения к сети, можно посмотреть в мониторе последовательного порта среды Arduino IDE после запуска которого на модуле нужно будет нажать кнопку "reset" (единственная кнопка которая имеется на данном модуле) чтобы этот адрес появился. Модуль, при этом, должен быть подключен к компьютеру через usb-uart переходник. Схему такого подключения а также то как загрузить скетчь в данный модуль, можно посмотреть на странице  https://electe.blogspot.com/2022/03/esp32-cam.html

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

В функции index_handler нужно найти вызов функции httpd_resp_set_hdr и поменять там строку GZIP на html чтобы можно было делать клиентскую часть на обычном html не конвертируя его в GZIP это удобнее и к томуже GZIP имеет меньший размер чем html только при больших размерах кода, при малых получается обратный эффект. Строка с HTML кодом клиентской части передается вторым параметром в функцию httpd_resp_sendstr. Чтобы текст можно было продолжить на следующей строке, можно ставить разделители обратные слеши. На фронтэнде т.е. клиентской стороне будет картинка с результатом обработки фотографии, кнопка чтобы сделать фотографию и выполнить обработку, кнопка чтобы включить/выключить освещение светодиодом и ссылка для перехода на страницу с результатом обработки фотографии. Также видно что в коде есть конструкция для того чтобы картинка бралась из сервера а не из кэша.

Алгоритм робертса в функции capture_handler будет реализовываться только в случае успешной конвертации фотографии в формат RGB888. Изображение состоит из пикселей, пиксель состоит из 3х составляющих красной, зеленой и синей на каждую состаляющую выделено 8 байт если усреднить составляющие то можно получить черно-белое изображение в данной реализации это делается на каждой итерации цикла для 4х соседних пикселей поэтому циклы проходят по всем пикселям кроме тех что в последней строке и последнем столбце для определения границы из правого нижнего пикселя вычитается левый верхний и из этой разницы берется модуль. Далее тоже самое производиться с оставшимися диагональными пикселями. Если берется модуль то, на самом деле, не важно какой из какого вычитаются главное чтобы это вычитание было перекресным в данной же реализации используется тренарный оператор для большей переносимости кода. После чего эти разницы по модулю складываются и получается результат, чем светлее пиксель тем резче переход цветов. Вот примерно такие получаются результаты обработки фотографий данным модулем с данным скетчем:

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