WebAssembly Powered Дополненная Реальность Судоку Решатель |
||
МЕНЮ Искусственный интеллект Поиск Регистрация на сайте Помощь проекту ТЕМЫ Новости ИИ Искусственный интеллект Разработка ИИГолосовой помощник Городские сумасшедшие ИИ в медицине ИИ проекты Искусственные нейросети Слежка за людьми Угроза ИИ ИИ теория Внедрение ИИКомпьютерные науки Машинное обуч. (Ошибки) Машинное обучение Машинный перевод Нейронные сети начинающим Реализация ИИ Реализация нейросетей Создание беспилотных авто Трезво про ИИ Философия ИИ Big data Работа разума и сознаниеМодель мозгаРобототехника, БПЛАТрансгуманизмОбработка текстаТеория эволюцииДополненная реальностьЖелезоКиберугрозыНаучный мирИТ индустрияРазработка ПОТеория информацииМатематикаЦифровая экономика
Генетические алгоритмы Капсульные нейросети Основы нейронных сетей Распознавание лиц Распознавание образов Распознавание речи Техническое зрение Чат-боты Авторизация |
2020-01-08 10:21 системы технического зрения, дополненная реальность, примеры ии Рождественские праздники-это прекрасное время для проведения "домашних" проектов и опробования новых вещей. В прошлом году я наблюдал за развитием WebAssembly и хотел создать интересный проект, который позволил мне использовать его с пользой. За последние пару недель я создал дополненную реальность Suduko solver: В этом проекте используется сборка WebAssembly из OpenCV (библиотека компьютерного зрения C++), Tensorflow (библиотека машинного обучения) и решателя, написанного в Rust. Он четко демонстрирует, как WebAssembly позволяет писать критически важные для производительности веб-приложения на широком диапазоне языков. Это сообщение в блоге дает краткий обзор кода для этого приложения, который можно найти на GitHub . Если вы новичок в WebAssembly и хотите узнать больше о проблеме, которую он решает, как он работает или что это такое, я бы тщательно рекомендовал руководство мультфильма Лина Кларка . Решатель Судоко На приведенной ниже диаграмме четко показаны шаги, связанные с определением местоположения головоломки судоку в изображении, решением головоломки, а затем отображением решения обратно на исходное изображение: Вкратце, шаги, применяемые к каждому видеокадру, выглядят следующим образом:
Мы рассмотрим каждый из этих шагов по очереди. Адаптивное обмолачивание Этот решатель судоку использует различные методы компьютерного зрения, все из которых полагаются на библиотеку OpenCV. OpenCV был запущен в 1999 году и вырос, чтобы стать популярным инструментарием компьютерного зрения благодаря своему обширному набору функций. Он также имеет различные дополнительные модули для ряда методов машинного обучения, включая нейронные сети. OpenCV написан на языке C++, с привязками для Python и Java. В 2018 году компилятор Emscripten был использован для добавления поддержки JavaScript. Несмотря на наличие "официальной" поддержки JavaScript / WebAssembly, OpenCV не так просто работать. Существует ограниченный набор OpenCV.JS учебники на веб-сайте, и один из первых шагов включает в себя создание библиотеки из исходного кода, а не задачу для слабонервных ?. Есть открытая проблема, требующая, чтобы они выпустили OpenCV.js через npm, который должен сделать жизнь намного проще-но пока не имеет большой тяги. На данный момент я просто открыл одну из своих демо-версий и скопировал необходимые файлы JS / wasm! Общая цель первых нескольких шагов обработки состоит в том, чтобы найти сетку судоку в изображении, первый из которых состоит в том, чтобы найти контур для различных форм в изображении. OpenCV поддерживает различные подходы к удержанию изображений, в этом случае мы не можем гарантировать даже освещение через сетку судоку, поэтому адаптивный пороговый подход является наиболее подходящим. В следующем коде показано, как создать буфер изображений OpenCV с помощью
Вы можете увидеть влияние этого преобразования на исходное изображение: Стоит отметить, что эти OpenCV.все операции js реализованы в C++ и скомпилированы в WebAssembly, различные Вы можете фактически увидеть, сколько времени тратится в коде OpenCV WebAssembly, записав профиль производительности: Код WebAssembly ясно виден в нижней части диаграммы пламени. Аппроксимация контуров Следующий шаг немного сложнее, нам нужно найти самый большой квадрат в изображении - который должен быть сеткой судоку. OpenCV имеет ряд методов для определения местоположения, аппроксимации и визуализации "контуров". Контур-это замкнутый контур, который описывает границу фигуры внутри изображения. Вы можете получить контуры из двоичного изображения с помощью
В OpenCV.js, конечно, чувствует себя довольно C-like, вы сначала должны создать матрицу иерархии и вектор-матрицу контуров перед вызовом Иерархия позволяет определить, какие контуры содержат другие, хотя здесь это не нужно - мы просто ищем самую большую четырехстороннюю форму. Однако это не так просто, как итерация по контурам, ищущим одну с четырьмя вершинами (т. е. углы). Контуры, возвращаемые Следующим шагом является аппроксимация каждого контура, уменьшение общего количества вершин и, как следствие, удаление некоторых деталей на уровне пикселей. Это достигается с помощью
Вышеописанное повторяется над каждой из контуров, получает аппроксимацию, затем определяет, имеет ли она четыре вершины, и если это так, координаты сохраняются. Передаваемое На следующем рисунке показаны приближенные контуры, цвет которых определяется числом вершин: На приведенном выше изображении контуры с темно-зеленоватым цветом имеют четыре вершины - вы можете видеть, что некоторые квадраты в сетке судоку были аппроксимированы более чем четырьмя вершинами, и в результате более высокое значение Эпсилона может быть уместным. Обратное Преобразование Перспективы Следующим шагом является использование геометрического преобразования для того, чтобы создать изображение только с сеткой судоку, преобразованной таким образом, что это квадрат. Еще раз, OpenCV имеет необходимые инструменты! Следующий код используется
Вот результат применения этого преобразования: Заключительным этапом обработки является удаление линий сетки, довольно простая задача, использующая функцию Region of Interest (ROI), которая позволяет применять операции к определенным областям буферов изображений. Я не буду вдаваться в подробности здесь. Распознавание чисел Следующий шаг-это весело один-идентификация чисел в сетке судоку. Я изначально спустился в кроличью нору здесь ... OpenCV имеет различные примеры, которые используют каскады Хаара для распознавания лиц, и мой первоначальный подход состоял в том, чтобы обучить каскад распознавать цифры. Однако, похоже, что этот метод больше не поддерживается в OpenCV 4.x, причем предпочтительным подходом является использование сверточных нейронных сетей. Тем не менее, OpenCV.JS build, который я использую, не включает модули машинного обучения, поэтому я решил посмотреть в другом месте, остановившись на TensorFlow (который, я думаю, является гораздо лучшим вариантом!). TensorFlow-это библиотека математики с фокусом машинного обучения,которая разрабатывается командой Google Brain. Они объявили о поддержке JavaScript в 2018 году, а поддержка WebAssembly всего несколько недель назад ! В отличие от OpenCV документация TensorFlow прекрасна-ясна, проста в использовании и актуальна ? Тензорный поток.js имеет всесторонний проработанный пример, который охватывает процесс обучения сверточной нейронной сети (CNN) для распознавания рукописных цифр , что было отличной отправной точкой для моего решателя судоку. Однако в моем случае мне нужно обучить свою сеть распознавать печатные цифры, а не рукописные. Если вы раньше не слышали о CNNs, я бы рекомендовал эту статью от Towards Data Science , которая включает в себя изображение ниже: Короче говоря, CNN-это метод глубокого обучения, при котором сложная многослойная нейронная сеть изучает различные операции свертки, применяемые к изображению для распознавания объектов из заданного обучающего набора. После того, как сеть была достаточно обучена, она может распознавать объекты в новых изображениях, т. е. те, с которыми она не была обучена. Я изменил пример из документации TensorFlow, в которой используется база данных рукописных цифр, заменив обучающие данные случайно сгенерированными цифрами. Они были представлены на холсте 20 x 20 с использованием различных шрифтов, веса шрифта и применения незначительных (рандомизированных) изменений размера шрифта, расположения и поворота. Вот несколько примеров:: процесс обучения включает в себя представление 1000s этих цифр в CNN, наряду с ожидаемым выходом, который представляет собой набор из десяти Весов, которые указывают на вероятность того, что изображение содержит конкретную цифру. Процесс обучения вносит небольшие коррективы в различные взвешивания глубоко внутри сети, при этом весь процесс повторяется 1000 раз, пока сеть не обеспечит достаточную точность распознавания. Один важный аспект, который я изучил методом проб и ошибок, заключается в том, что наряду с обучением сети распознавать каждую из десяти цифр, я должен также обучать ее распознавать пустые квадраты. Следовательно, мой CNN обеспечивает 11 выходных вероятностей. После обучения сеть, включая полученные весовые коэффициенты, можно сохранить. Весь процесс был действительно довольно быстрым-около одной минуты на моей машине. API TensorFlow позволяет выполнять несколько прогнозов за один раз. Процесс создания модели и подачи ее с данными theimage в подходящем формате действительно прост:
Прогнозирование для каждой ячейки представляет собой массив из 11 значений, дающий вероятность каждой цифры, или пустую ячейку. Следующий код создает строковое представление сетки судоку на основе прогноза для каждой ячейки:
Типичный вывод выглядит следующим образом (я вручную завернул toi в строку, чтобы было понятно, что это сетка):
Я надеялся использовать WebAssembly build of TensorFlow, однако я наткнулся на загвоздку. Текущий релиз находится в alpha и не поддерживает все функции TensorFlow - при использовании alpha build он жаловался, что Решение головоломки Поскольку и OpenCV, и TensorFlow являются библиотеками C++, я подумал, что было бы интересно немного перепутать вещи и использовать Rust для следующего шага. Sudoko Solvers похожи на игру жизни, оба являются популярными проблемами программирования, и это не заняло много времени, чтобы найти приличный выглядящий решатель, написанный в ржавчине . RUST tooling для WebAssembly действительно первоклассный, учитывая, что мои знания о ржавчине (очень) ограничены, я смог встать и с помощью полнофункционального решателя менее чем за час. Я использовал шаблон wasm-pack, следуя инструкциям в книге Rust ? и WebAssembly?, чтобы создать свой скелетный проект. Затем я добавил ящик судоку и обновил созданный код следующим образом:
Следующая команда строит проект, с
Результатом этой сборки является небольшой (70 КБ) модуль wasm и сопутствующий файл JavaScript, который извлекает модуль wasm и адаптирует функции, выполняя различные преобразования типов. Здесь добавляется большая часть значения, WebAassembly поддерживает только числовые типы, однако приведенный выше код экспортирует функцию со строковым аргументом и возвращаемым значением. Wasm-bindgen проект, автоматически генерирующий привязки для упрощения связи между JavaScript и Rust (компилируется в WebAassembly), в этом случае он обрабатывает кодирование и декодирование строк в линейную память, что значительно снижает усилия, связанные с использованием кода Rust в интернете. Использование этого модуля WebAssembly не может быть проще:
Рендеринг решения и слияние Последние несколько шагов действительно довольно просты, я не буду углубляться в детали, вы уже видели методы на практике. Решение выводится на новое изображение 180 x 180, используя API Canvas для вывода каждой цифры. OpenCV Вот окончательное объединенное изображение: Я уверен, что должен выглядеть счастливее с конечным результатом! Если вы хотите попробовать его для себя , проект размещается на страницах GitHub, и исходный код также доступен . Пожалуйста, обратите внимание, поскольку это был забавный проект, я не хотел тратить время (и угнетать себя), свернув, транспонировав или полифудируя. Если Ваш браузер не поддерживает модули ES, async / await и различные другие современные функции, он не будет работать для вас! Выводы Это был забавный хобби-проект и аккуратная демонстрация того, как WebAssembly позволяет использовать целый ряд различных библиотек, написанных на разных языках (даже если я не мог фактически использовать сборку wasm TensorFlow). Конечные приложения работают довольно хорошо, распознавая сетки судоку в различных различных ориентациях с множеством различных шрифтов и стилей визуализации. Одна вещь, с которой он борется,-это размытие движения, я обнаружил, что если я перемещаю сетку довольно быстро, размытие изображения препятствует первоначальному адаптивному пороговому обнаружению края. Что касается скорости обработки, то на моем компьютере требуется около 70 мс для выполнения полного конвейера (порог, контур, решатель, слияние,...), которого достаточно. На моем iPhone он заметно медленнее, и частота кадров на самом деле недостаточно хороша для достижения иллюзии, которую пытается представить AR. Я уверен, что есть место для улучшения, например, я не тратил много времени на эксперименты с размером изображения, уменьшение разрешения сетки (которое в настоящее время составляет 180 x 180) значительно улучшило бы производительность. Кроме того, пул веб-работников может использоваться для параллельной обработки этого конвейера. Более радикальные изменения могут быть сделаны, складывая некоторые из этапов обработки в CNN, возможно, можно будет обучить сеть распознавать сетку в немодифицированном исходном изображении. Однако это потребует значительных инвестиций в сбор учебных данных и может не дать более высокой точности. Последнее замечание, в то время как основная часть работы в настоящее время выполняется в различных модулях WebAssembly, написанных на C++ и Rust, все еще существует довольно много JavaScript-кода клея, необходимого для координации приложения. Недавно объявленные предложения типов интерфейсов должны в конечном итоге устранить необходимость написания кода JavaScript для связи между модулями wasm, написанными на разных языках. Через несколько лет я мог бы, возможно, написать свой конвейер решателя в Go, напрямую связываясь с моей библиотекой машинного зрения C++ и моим решателем ржавчины! Источник: blog.scottlogic.com Комментарии: |
|