Изменение фона веб-камеры теперь не ограничивается Zoom, я просто сделал это в браузере с помощью модели body-pix tensorflow.js

Был ли у вас момент, когда, просматривая эти симпатичные селфи из путешествий в социальных сетях, вы говорили себе: «Хотел бы я быть там»? Угадайте, что мы собираемся воплотить в жизнь это сегодня. С помощью новейшей технологии сегментации людей мы можем отделить часть тела от фона на уровне пикселей.

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

В этой статье я покажу вам, как создать приложение Selfie Anywhere, которое может погрузить вас в эти прекрасные сцены путешествий, изменив фон селфи в режиме реального времени. Вам не нужен ни Photoshop, ни зеленый экран. Давайте повеселимся и посчитаем «3, 2, 1… Say Cheese»!

Попробуйте сами, демо находится по ссылке ниже:



Выполнение

Вы сделали несколько селфи выше и показали их своим друзьям? Надеюсь, вам понравится, это приложение использует продвинутый метод под названием Сегментация тела, который может идентифицировать человека в изображении или видеопотоке и отделить тело переднего плана от фона.

В начале этого года Google выпускает BodyPix, модель машинного обучения с открытым исходным кодом, которая позволяет сегментировать человека и части тела в браузере с помощью TensorFlow.js. Я был поражен этой технологией, и мне пришла в голову идея создать вышеупомянутое приложение Selfie Anywhere. Следуйте за мной ниже, чтобы узнать, как я это реализовал.

# Шаг 1. Включите tfjs и body-pix

Прежде всего, просто включите сценарий Tensorflow.js и его body-pix модель в раздел ‹head› файла html.

<script src="https://cdn.jsdelivr.net/npm/@tensorflow/[email protected]"></script>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/[email protected]"></script>

Или вы можете установить его через npm для использования в проекте TypeScript / ES6

npm install @tensorflow-models/body-pix

# Шаг 2: потоковое видео с веб-камеры в браузер

Для потоковой передачи данных с веб-камеры в браузер я использую библиотеку JavaScript navigator.mediaDevices.getUserMedia. Чтобы узнать больше об этом, обратитесь к моей предыдущей статье:



# Шаг 3: Загрузите модель BodyPix

Чтобы обработать сегментацию, нам сначала нужно загрузить предварительно обученную модель BodyPix, вызвав API bodyPix.load(modelConfig). BodyPix поставляется с несколькими различными версиями модели, с разными характеристиками производительности, которые зависят от размера модели и времени прогнозирования с точностью.

По умолчанию BodyPix загружает архитектуру MobileNetV1 с множителем 0.75. Это рекомендуется для компьютеров с графическими процессорами среднего / нижнего уровня. Для мобильных устройств рекомендуется модель с множителем 0.50. Архитектура ResNet рекомендуется для компьютеров с еще более мощными графическими процессорами.

bodyPix.load({
    architecture: 'MobileNetV1',
    outputStride: 16,
    multiplier: 0.75,
    quantBytes: 2
})

# Шаг 4: сегментация тела

Затем мы начинаем передавать поток веб-камеры через модель body-pix для выполнения сегментации человека, вызывая API net.estimatePersonSegmentation(video, outputStride, segmentationThreshold). Он сегментирует изображение на пиксели, которые являются и не являются частью человека. Он возвращает двоичный массив с 1 для пикселей, которые являются частью человека, и 0 в противном случае. Размер массива соответствует количеству пикселей в изображении.

net.segmentPerson(webcamElement,  {
    flipHorizontal: true,
    internalResolution: 'medium',
    segmentationThreshold: 0.5
  })
  .then(personSegmentation => {
    if(personSegmentation!=null){
        drawBody(personSegmentation);
    }
});
cameraFrame = requestAnimFrame(detectBody);

flipHorizontal по умолчанию - false. Если сегментацию и позу следует перевернуть / отразить по горизонтали. Это должно быть установлено в true для видео, где видео по умолчанию переворачивается по горизонтали (например, веб-камера), и вы хотите, чтобы сегментация и поза возвращались в правильной ориентации.

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

Он возвращает Promise, который разрешается с помощью объекта SemanticPersonSegmentation. Несколько человек на изображении объединяются в единую двоичную маску. В дополнение к полям width, height и data он возвращает поле allPoses, которое содержит позы для всех людей. Массив данных для всех людей, содержащий 307200 значений, по одному на каждый пиксель изображения 640x480.

{
  width: 640,
  height: 480,
  data: Uint8Array(307200) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, …],
  allPoses: [{"score": 0.4, "keypoints": […]}, …]
}

# Шаг 5: удалить фон

В приведенной выше функции мы получаем двоичный массив, чтобы указать, что пиксели принадлежат телу или нет, теперь мы можем использовать его для удаления фона и рисования тела только на холсте. В объекте ImageData каждый пиксель содержит значения красного, зеленого, синего и альфа (прозрачности), трюк для удаления фона заключается в установке значения transparency пикселя на 0.

const canvasPerson = document.getElementById("canvasPerson");
let contextPerson = canvasPerson.getContext('2d');
 
function drawBody(personSegmentation)
{
    contextPerson.drawImage(camera, 0, 0, camera.width, camera.height);
    var imageData = contextPerson.getImageData(0,0, camera.width, camera.height);
    var pixel = imageData.data;
    for (var p = 0; p<pixel.length; p+=4)
    {
      if (personSegmentation.data[p/4] == 0) {
          pixel[p+3] = 0;
      }
    }
    contextPerson.imageSmoothingEnabled = true;
    contextPerson.putImageData(imageData,0,0);
}

# Шаг 6. Наложение холста поверх фонового изображения.

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

<video id="webcam" autoplay playsinline width="640" height="480"></video>
<div id="selfie-container">
    <div id="background-container"></div>
    <canvas id="canvasPerson" width="640" height="480"></canvas>
</div>

Применение стиля CSS ниже

#background-container {
    height: 100vh;
    width: 100vw;
    background-image: url(../images/greatwall.jpg);
    background-position: center center;
    background-repeat: no-repeat;
    background-size: cover;
    background-color: transparent;
}
 
#canvasPerson{
 background-color: transparent;
 position: absolute;
 width: 100vw;
 height: auto;
 z-index: 9999;
 margin: auto;
 top: 0;
 bottom: 0;
 left: 0;
 right: 0;
 margin-left: auto;
 margin-right: auto;
 -moz-transform: scale(-1, 1);
 -webkit-transform: scale(-1, 1);
 -o-transform: scale(-1, 1);
 transform: scale(-1, 1);
 filter: FlipH;
}

# Шаг 7. Сделайте снимок экрана.

Для съемки я использую стороннюю библиотеку JavaScript html2canvas.js. Он позволяет делать снимки экрана веб-страниц или их частей прямо в браузере пользователя.

$("#take-photo").click(function () {
    beforeTakePhoto();
    var captureElement= document.getElementById('selfie-container');
    var appendElement= document.getElementById('webcam-container');
    html2canvas(captureElement).then(function(canvas) {
        canvas.id='captureCanvas';
        appendElement.appendChild(canvas);
        document.querySelector('#download-photo').href = canvas.toDataURL('image/png');
        afterTakePhoto();
    });
});

Вот и все для кода! В остальном демо просто выглядит красиво. Выберите одну из этих захватывающих сцен, установите свою любимую позу и улыбнитесь!

Репозиторий GitHub

Вы можете скачать полный код вышеуказанной демонстрации по ссылке ниже:



Вывод

Достижения в технологиях сегментации экземпляров теперь перспективны для многих областей, начиная от беспилотных автомобилей и заканчивая медицинской диагностикой. Благодаря нейронной сети с глубоким обучением модели становятся все более точными. Я надеюсь, что эта статья - только начало вашего пути к тому, чтобы узнать больше о сегментации изображений и компьютерном зрении.

Спасибо за чтение. Если вам понравилась эта статья, поделитесь ею в Facebook или Twitter. Дайте мне знать в комментарии, если у вас возникнут вопросы. Следуйте за мной на GitHub и Linkedin.