WebAssembly — это технология, позволяющая запускать в браузере скомпилированный из разных языков код.
Наша библиотека написана на С++ и портирована в WebAssembly при помощи Emscripten.
Для максимального охвата устройств мы предоставляем 4 набора библиотек, каждая из которых должна загружаться в зависимости от поддержки конкретных фич браузера.
Описание сборок:
nosimd.nothreads
— универсальная сборка, имеющая поддержку на большинстве устройств.simd.nothreads
— самая быстрая сборка.simd.threads
— сборка для постоянных задач по распознаванию. Поддержка многопоточности требует времени на инициализацию воркеров, которые по нашим подсчетам могут занимать больше времени, чем выполнение простой задачи с помощью сборки simd.nothreads
.nosimd.threads
— сборка, для редких случаев.SIMD — это набор инструкций, который позволяет значительно увеличить скорость вычислений.
THREADS — поддержка многопоточности. Возможность распараллеливать вычисления возможна через создание дополнительных веб-воркеров, использующих общий SharedArrayBuffer
.
Для работы с ним необходимо дополнительно настраивать заголовки COOP и COEP на сервере.
Поддержку simd-инструкций и многопоточности в браузерах можно узнать с помощью библиотеки wasm-feature-detect
.
Настройка веб-сервера является обязательной для оптимальной работы wasm.
Веб-сервер должен возвращать Content-Type: application/wasm
для файлов с расширением *.wasm
.
Веб-сервер должен поддерживать компрессию файлов c расширением .wasm
. Wasm файлы хорошо сжимаются и это значительно позволит сократить время доставки файлов до клиента.
Убедитесь в наличии заголовка content-encoding
у файла *.wasm
при отдаче сервером в devtools, или используйте curl curl -H "Accept-Encoding: gzip" -I https://*.wasm
Рекомендуем отдавать wasm
файлы уже сжатыми, чтобы не нагружать сервер сжатием файлов на лету на каждый запрос.
Для начала возьмём скомпилированный в WebAssembly модуль распознавания изображений от Smart Engines.
Он не требует настройки, его нужно просто положить в директорию проекта.
Для того, чтобы не блокировать основной поток исполнения тяжёлыми задачами по распознаванию изображения, для общения с wasm-модулем мы будем использовать web worker, работающий в отдельном потоке.
Web worker является посредником в общении клиентского JavaScript-кода и wasm-модуля.
Теперь создадим HTML-страницу.
Для того чтобы распознавать изображения в реальном времени, на странице нам понадобятся:
Элементы video
и canvas
для вывода изображения с камеры:
<video id="video" class="video" playsinline muted autoplay></video>
<canvas id="canvas" class="canvas"></canvas>
Кнопки для начала распознавания изображения и сверки лиц:
<button id="scan-button" class="button">
Сканировать документ
</button>
<button id="capture-face-button" class="button">
Сверить лицо
</button>
Блок для вывода результатов распознавания:
<div id="result-wrapper" class="result-wrapper">
<h3>Результат сканирования</h3>
<div id="output"></div>
</div>
Теперь подключим к странице JavaScript-файл.
В JavaScript-файле запросим видеопоток с камеры:
stream = await navigator.mediaDevices
.getUserMedia({ video: { facingMode: { ideal: "environment" } } })
И направим его в наш видео-элемент на странице:
const videoEl = document.querySelector("#video")
videoEl.srcObject = stream
await videoEl.play()
Теперь на странице отображается видео с камеры.
Передадим видео в canvas
.
Это нужно для того чтобы можно было захватывать отдельные кадры из видео и передавать на распознавание.
const canvasEl = document.querySelector("#canvas")
const ctx = canvasEl.getContext("2d", { willReadFrequently: true })
const animate = function () {
ctx.drawImage(videoEl, 0, 0, canvasEl.width, canvasEl.height)
requestAnimationFrame(animate)
}
animate()
Затем подключим воркер и передадим ему тип документа, который мы собираемся распознать:
SEWorker = new Worker("./worker.js")
SEWorker.postMessage({
requestType: "createSession",
docData: "default:rus.passport.national"
})
По нажатию на кнопку, возьмём кадр из видео и отправим воркеру на распознавание:
const scanButtonEl = document.querySelector("#scan-button")
scanButtonEl.addEventListener("click", async () => {
SEWorker.postMessage({
requestType: "frame",
imageData: canvasEl.getContext("2d", { willReadFrequently: true })
.getImageData(0, 0, canvasEl.width, canvasEl.height)
})
})
В процессе работы воркер возвращает координаты распознаваемых элементов, которые мы можем подсвечивать на видео.
В сообщении от воркера получим результат и выведем его на страницу.
Результат содержит текст и отдельные элементы изображения для удобства проверки.
SEWorker.onmessage = function (message) {
switch (message.data.requestType) {
case "result":
let result = message.data
if (Object.keys(result.data).length === 0) {
console.log("Document not found")
SEWorker.postMessage({ requestType: "reset" })
return
}
printResult(result)
canvasHandler.clear(canvasOverlayEl)
SEWorker.postMessage({ requestType: "reset" })
break
}
Минимальное веб-приложение с возможностью распознавания изображений готово.
Заказать продукт
Для заказа решений, получения подробной информации или триал версий
заполните приведенную ниже форму, и мы обязательно с Вами свяжемся.