Добро пожаловать, в этой статье мы возьмем предварительно обученную модель TensorFlow.js BlazeFace и используем ее для выполнения обнаружения лиц на живой веб-камере. кормить. Это продемонстрирует ключевые понятия для TensorFlow.js и базового JavaScript. Наслаждаться!

Оглавление:

  1. Структура папок и файлов
  2. Начальные константы DOM и проверка веб-камеры
  3. Загрузка нашей модели и включение веб-камеры
  4. Составление и отображение наших прогнозов

1. Настройка HTML и файловая структура

Для начала нам нужно создать файл index.html и заполнить его скелетом HTML следующим образом.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>TensorflowJS</title>
</head>
<body>
</body>
</html>

Затем мы можем заполнить некоторые важные теги для нашего HTMLтела. Начиная с нескольких тегов h1 и p для текста, информирующего пользователя. Затем мы создаем раздел для нашей демонстрации и заполняем его текстом и блоком div, содержащим выход с камеры. Он будет содержать как нашу кнопку Включить веб-камеру, так и видео размером 640x480. Обратите внимание, что размер может быть изменен, но модель должна быть соответствующим образом скорректирована.

<h1>Facial Recognition using a TensorflowJS pre trained model</h1>
<p>The model may take some time to load, the button will be available to click once it is.</p>
<section id="demo" class="invisible">
    <p>Keep your face in frame and the model should be able to recognize it and draw a bounding box!</p>
    <div id="liveView" class="camView">
        <button id="webcamButton">Enable Webcam</button>
        <video id="webcam" autoplay muted width="640" height="480"></video>
    </div>
</section>

Теперь мы можем добавить ссылки на наш CSS, базовый JavaScript, TensorflowJS и модель, которую мы будем использовать, известную как BlazeFace. Эта модель находится в открытом доступе, и вы можете найти информацию о ней, как и о многих других, в профиле TensorFlow на Github. Мы импортируем CSS в заголовок и JavaScript в нижнюю часть тела. Мы также можем добавить наши файлы style.css и index.js, пока мы это делаем.

<!-- Import CSS -->
<link rel="stylesheet" href="style.css">
.
.
.
<!-- Page Specific Javascript -->
<script src="index.js" defer></script>
<!-- Import TensorFlow.js library -->
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs/dist/tf.min.js" type="text/javascript"></script>
<!-- Load the blazeface model to use to recognize things in images -->
<script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/blazeface"></script>

На данный момент ваш живой сайт должен выглядеть примерно так: Это функционально, но не очень эстетично, поэтому, возможно, нам придется немного украсить его.

Теперь мы можем настроить простой CSS, чтобы сайт выглядел лучше и чтобы пользователи не нажимали кнопку веб-камеры до загрузки модели. Мы также настраиваем свойства наших классов highlighter и featureIndicator, которые позже будут использоваться для отображения ограничивающей рамки для лица и кругов, представляющих ключевые черты лица.

body {
font-family: arial, sans-serif;
color: #3D3D3D;
}
h1 {
color: #7711ebee;
font-size: 2.5rem;
font-weight: bold;
}
video {
display: block;
}
section {
opacity: 1;
transition: opacity 500ms ease-in-out;
}
.removed {
display: none;
}
.invisible {
opacity: 0.2;
}
.camView {
position: relative;
float: left;
width: calc(100% - 20px);
margin: 10px;
cursor: pointer;
}
.camView p {
position: absolute;
padding: 5px;
background-color: rgba(76, 0, 255, 0.85);
color: #FFF;
border: 1px dashed rgba(255, 255, 255, 0.7);
z-index: 2;
font-size: 12px;
}
.highlighter {
background: rgba(76, 0, 255, 0.2);
border: 1px dashed #fff;
z-index: 1;
position: absolute;
}
.featureIndicator {
background: rgb(255, 174, 0);
z-index: 1;
position: absolute;
border-radius: 50%;
}

Теперь ваш сайт должен выглядеть примерно так.

2. Исходные константы DOM и проверка веб-камеры

Теперь, когда у нас есть HTMLскелет и простые стили, мы можем начать структурировать наш JavaScript. Мы будем хранить все наши JS вместе в нашем файле index.js, который ранее был импортирован с помощью тега скрипта. Для начала мы определимнеобходимые константы для подключения к важным элементам в DOM. К ним относятся наше подключение к веб-камере, просмотр в реальном времени, где мы будем отображать наш выходной видеопоток (после запуска модели), наш общий демонстрационный раздел, который в настоящее время «невидим», и нашу кнопку веб-камеры, которую мы нажмем, чтобы включить нашу веб-камеру.

const video = document.getElementById('webcam');
const liveView = document.getElementById('liveView');
const demosSection = document.getElementById('demo');
const enableWebcamButton = document.getElementById('webcamButton');

Далее нам нужно создать функцию, чтобы проверить, поддерживается ли пользовательское мультимедиа (чтобы получить доступ к веб-камере), и добавить прослушиватель событий для нашей кнопки. Обратите внимание: поскольку мы еще не определили функцию enableCam, на этом этапе мы получим ошибку JavaScript.

getUserMediaSupported() {    
   return !!(navigator.mediaDevices && navigator.mediaDevices.getUserMedia);  
}
if (getUserMediaSupported()) {            enableWebcamButton.addEventListener('click', enableCam);
} else {    console.warn('getUserMedia() is not supported by your browser');
}

3. Загрузка нашей модели и включение веб-камеры

Теперь нам нужно загрузить нашу модель и дождаться завершения этого действия, так как это может занять некоторое время. Как только он будет загружен, мы можем удалить наш невидимый класс для этого раздела. Обратите внимание, что мы по-прежнему не определили enableCam как функцию для нашего предыдущего прослушивателя событий, и поэтому все равно получим ошибку JavaScript.

blazeface.load().then(function (loadedModel) {
    blazeModel = loadedModel;
    demosSection.classList.remove('invisible');
});

Затем мы можем включить камеру после того, как модель будет загружена, и настроить исходный объект нашего видео.

function enableCam(event) {
    if (!blazeModel) {
        return;
    }
    event.target.classList.add('removed');
    const constraints = {
        video: true
    };
    navigator.mediaDevices.getUserMedia(constraints).then(function(stream) {
    video.srcObject = stream;
    video.addEventListener('loadeddata', predictWebcam);
});
}

4. Создание и отображение наших прогнозов

Когда кнопка включения веб-камеры заработает, мы можем начать делать прогнозы для нашего потока с веб-камеры, используя модель BlazeFace, а затем заполнить видеопоток с несколькими разделами-индикаторами, использующими пару вспомогательных функций. Чтобы делать прогнозы, мы сначала вызываем метод estimateFaces модели. Затем мы обязательно удаляем все старые элементы div, которые могут присутствовать в последнем кадре. После этого нам нужно перебрать наши прогнозы (поскольку может быть несколько лиц), проверить, превышает ли определенность определенный >threshold и извлеките информацию, чтобы создать разделы индикаторов.

function predictWebcam() {
    const returnTensors = false;
    blazeModel.estimateFaces(video, returnTensors).then(function (predictions) {
        for (let i = 0; i < children.length; i++) {
            liveView.removeChild(children[i]);
        }
        children.splice(0);
        for (let n = 0; n < predictions.length; n++) {
            if (predictions[n].probability > 0.66) {
                let predictionsArray = predictions[n];
                let boundStart = predictionsArray.topLeft;
                let boundEnd = predictionsArray.bottomRight;
                let landmarks = predictionsArray.landmarks;
                for (let k=0; k < landmarks.length; k++) {
                    createFeatureIndicator(landmarks[k][0], landmarks[k][1]);
                }
                createFaceBoundBox(boundStart, boundEnd);
            }
        }
        window.requestAnimationFrame(predictWebcam);
    });
}

Теперь нам нужно определить вспомогательные функции для createFeatureIndivator и createFaceBoundBox, на которые мы ссылались ранее, чтобы фактически заполнить видео нашими элементами div. Эти вспомогательные функции служат для создания наших элементов DOM и добавления их в наш liveViewdiv. Местоположение и размер этих дочерних элементов берутся из самой модели. Мы также инициализируем переменную blazeModel, чтобы расширить область ее применения.

function createFaceBoundBox(start, end) {
    let size = [end[0] - start[0], end[1] - start[1]];
    const highlighter = document.createElement('div');
    highlighter.setAttribute('class', 'highlighter');
    highlighter.style = 'left: ' + start[0] + 'px; top: '
        + start[1] + 'px; width: '
        + size[0] + 'px; height: '
        + size[1] + 'px;';
    liveView.appendChild(highlighter);
    children.push(highlighter);
}
function createFeatureIndicator(x, y) {
    const featureIndicator = document.createElement('div');
    featureIndicator.setAttribute('class', 'featureIndicator');
    featureIndicator.style = "left: " + x + "px;"
        + "top: " + y + "px;"
        +  "width: .5rem; height: .5rem;"
    liveView.appendChild(featureIndicator);
    children.push(featureIndicator);
}
var blazeModel = undefined;

Благодаря этому наша веб-страница теперь полностью функциональна и должна работать и делать прогнозы на основе данных с веб-камеры!

Надеюсь, вам было интересно читать, так как мне очень понравилось писать эту статью. Заботиться!