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

Опубликовано: 2022-03-10
Краткое резюме ↬ В этой статье мы расскажем, как комбинировать машинное обучение, вариативные шрифты и сетки CSS для создания макетов, которые реагируют на близость, наклон и количество лиц пользователей.

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

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

Что такое тензорный поток?

Tensorflow — это платформа с открытым исходным кодом от Google для машинного обучения. Машинное обучение — это область компьютерных наук, изучающая алгоритмы, которые учатся распознавать сложные отношения и повторяющиеся шаблоны из изображений, звуковых дорожек, временных рядов, естественного текста и данных в целом. Эти алгоритмы генерируют математические модели (также называемые обученными моделями), которые представляют собой своего рода схемы, которые можно использовать для принятия решений на основе входных данных. Если вы хотите приблизиться к теме, Чарли Джерард написал об ML для разработчиков внешнего интерфейса здесь, на Smashing Mag.

Tensorflow предоставляет множество инструментов для разработчиков ИИ, специалистов по данным, математиков, но не паникуйте, если анализ данных не является вашим хлебом насущным! Хорошая новость заключается в том, что вам не нужно быть экспертом, чтобы использовать его, если вы используете готовые модели, как мы собираемся.

Модели Tensorflow доступны для использования в Интернете с их SDK для JavaScript.

Настраивать

Чтобы начать использовать алгоритмы распознавания лиц, нам нужно выполнить несколько шагов:

  • загрузите SDK Tensorflow.
  • загрузить библиотеку Facemesh, содержащую математическую модель.
  • получить доступ к камере пользователя и передать ее видеоэлементу HTML. Facemesh будет анализировать кадры из тега видео, чтобы обнаружить присутствие лиц.

В этих проектах мы собираемся использовать Tensorflow через CDN, но он также доступен в NPM, если вы предпочитаете сборщик:

 <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-core"></script> <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-converter"></script> <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-backend-webgl"></script>

Tensorflow сам по себе не справляется, поэтому нам нужно добавить Facemesh, библиотеку, которая построена поверх фреймворка ML и предоставляет уже обученную модель для распознавания лиц:

 <script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/facemesh"></script>

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

 // create and place the video const video = document.createElement('video'); document.body.appendChild(video); // setup facemesh const model = await facemesh.load({ backend: 'wasm', maxFaces: 1, }); async function detectFaces() { const faces = await model.estimateFaces(video); console.log(faces); // recursively detect faces requestAnimationFrame(detectFaces); }

Теперь мы готовы запросить у пользователя разрешение на доступ к потоку его камеры с помощью тега видео:

 // enable autoplay video.setAttribute('autoplay', ''); video.setAttribute('muted', ''); video.setAttribute('playsinline', ''); // start face detection when ready video.addEventListener('canplaythrough', detectFaces); // stream the camera video.srcObject = await navigator.mediaDevices.getUserMedia({ audio: false, video: { facingMode: 'user', }, }); // let's go! video.play();

Метод navigator.mediaDevices.getUserMedia запросит разрешение и начнет транслировать камеру в элемент видео. После принятия камера начнет потоковую передачу на тег видео, а консоль браузера будет регистрировать информацию о лице, обнаруженную Facemesh.

Обратите внимание, что для доступа к камере требуется безопасное https-соединение или локальный хост: вы не можете просто открыть файл index.html. Если вы не знаете, как настроить локальный сервер проверки http-сервера для Node, или следуйте этому руководству для Python или этому для PHP.

Еще после прыжка! Продолжить чтение ниже ↓

Пример 1. Настройка типографики с помощью камеры смартфона

Мы путешествуем по сети везде с помощью нашего смартфона. Было время, не так давно, когда мы ездили в переполненных поездах или автобусах и держали смартфон очень близко к глазам, потому что не было места. Во многих моментах и ​​местах нашего дня мы часто меняем положение и наклон смартфона, даже если смотрим один и тот же сайт. Расстояние между глазами и смартфоном влияет на наши возможности чтения. Оценивая это расстояние, мы можем настроить микротипографию, чтобы оптимизировать глифы для более близкого или более отдаленного чтения.

Под распознаванием лиц понимается, конечно же, и распознавание положения глаз. Мы можем использовать данные, предоставленные Facemesh, для расчета размера нашего лица по отношению ко всему изображению, снятому камерой. Можно предположить, что чем больше наше лицо, тем ближе мы к экрану. Мы можем настроить шкалу от 0 (одна рука на расстоянии — лицо примерно занимает половину камеры) до 1 (приклеено к экрану) и определить текущее значение делением на сегменты:

 async function detectFaces() { const faces = await model.estimateFaces(video); if (faces.length === 0) { // is somebody out there? return requestAnimationFrame(detectFaces); } const [face] = faces; // extract face surface corners let { bottomRight, topLeft} = face.boundingBox; // calculate face surface size let width = bottomRight[0] - topLeft[0]; let height = bottomRight[1] - topLeft[1]; let videoWidth = video.videoWidth; let videoHeight = video.videoHeight; let adjustWidth = videoWidth / 2; let adjustHeight = videoHeight / 2; // detect the ratio between face and full camera picture let widthRatio = Math.max(Math.min((width - adjustWidth) / (videoWidth - adjustWidth), 1), 0); let heightRatio = Math.max(Math.min((height - adjustHeight) / (videoHeight - adjustHeight), 1), 0); let ratio = Math.max(widthRatio, heightRatio); // recursively detect faces requestAnimationFrame(detectFaces); }
Представление лица пользователя в виде сегментов размещается внутри рамки смартфона, чтобы указать, какую площадь экрана занимает лицо.
Два примера признаков, обнаруженных Facemesh, таких как положение и наклон глаз, носа и рта. Мы можем использовать площадь между точками, чтобы вычислить близость к камере смартфона. (Большой превью)

Теперь, когда мы рассчитали ratio , пришло время сделать что-то волшебное, передав значение в таблицу стилей:

 document.documentElement.style.setProperty('--user-distance', ratio);

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

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

 .main-text { --min-opsz: 10; --max-opsz: 15; --opsz: calc(var(--min-opsz) + (var(--user-distance) * (var(--max-opsz) - var(--min-opsz)))); ... font-family: 'Amstelvar', serif; font-variation-settings: 'opsz' var(--opsz); }

Вы можете увидеть это вживую здесь. Обратите внимание, что этот пример — всего лишь демонстрация того, как работает технология. Типографские изменения должны быть почти незаметны для глаз пользователя, чтобы действительно обеспечить лучший читательский опыт. Здесь мы использовали формы глифов, но использование цветов для увеличения или уменьшения контраста — еще одно хорошее решение. Другой эксперимент состоял в том, чтобы определить угол лица, чтобы вычислить перспективу чтения, модифицируя надстрочные и подстрочные элементы и высоту букв:

См. Pen [Facemesh и восходящие/нисходящие] (https://codepen.io/smashingmag/pen/oNxrYop) Эдоардо Кавацца.

См. Pen Facemesh и восходящие/нисходящие элементы Эдоардо Кавацца.

Случай № 2: настройка макета при изменении количества просматривающих людей

Во втором случае мы собираемся изменить макет в зависимости от количества людей, смотрящих на экран. Мы можем представить эссе, отображаемое на интерактивной доске в контексте школьного класса. Этот сценарий немного отличается от того, который обнаруживается устаревшим медиа-запросом проекции, поскольку мы хотим настроить макет страницы, если количество просматривающих учеников меньше или больше, чем 10. Когда в классе находится всего несколько учеников, они можно смело подходить к доске, но если присутствует весь класс, возможно, места не хватает и нужно изменить макет, чтобы было меньше (и больше) вещей.

Нам просто нужно внести несколько изменений в предыдущий сценарий, чтобы правильно определить количество лиц, смотрящих на доску. Во-первых, нам нужно указать Facemesh обнаруживать несколько лиц:

 const model = await facemesh.load({ backend: 'wasm', maxFaces: 30, });

И затем мы должны передать это число в таблицу стилей:

 async function detectFaces() { const faces = await model.estimateFaces(video); document.documentElement.style.setProperty('--watching', faces.length); // recursively detect faces requestAnimationFrame(detectFace); }

Опять же, мы могли бы использовать это значение, чтобы просто увеличить размер шрифта, но наша цель — предоставить совершенно другой макет. Сетчатые макеты CSS могут помочь нам в этой миссии. Этот спроецированный документ представляет собой длинную форму с отступом, содержащим связанные изображения:

 <section> <article> <h1>...</h1> <h2>...</h2> <p>...</p> </article> <aside> <img src="..." alt="..." /> </aside> </section>

И это его макет по умолчанию:

 section { display: grid; grid-template-columns: repeat(12, 1fr); grid-column-gap: 1em; width: 120ch; max-width: 100%; padding: 1em; } section article { grid-column: 1 / -5; } section aside { grid-column: 7 / -1; }
Слева: когда смотрят более 10 человек, мы отдаем приоритет основному тексту, используя все доступные столбцы и перемещая изображения после текста. Справа: макет страницы с использованием 12 столбцов с активными направляющими инспектора сетки Firefox. Все 12 колонок используются для основного текста, 4 — для изображений после него.
Слева : макет страницы по умолчанию использует 8 из 12 столбцов для подробного текста, а оставшиеся 4 — для изображений. Справа : когда смотрят более 10 человек, мы отдаем приоритет основному тексту, используя все доступные столбцы и перемещая изображения после текста. (Большой превью)

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

 :root { --watching: 10; } section { /** The maximum number of people watching for the default layout */ --switch: 10; /** The default number of columns for the text */ --text: 8; /** The default number of columns for the aside */ --aside: 4; grid-template-columns: repeat(calc(var(--text) + var(--aside)), 1fr); } section article { /** * Kinda magic calculation. * When the number of people watching is lower than --switch, it returns -2 * When the number of people watching is greater than --switch, it returns -1 * We are going to use this number for negative span calculation */ --layout: calc(min(2, (max(var(--switch), var(--watching)) - var(--switch) + 1)) - 3); /** * Calculate the position of the end column. * When --layout is -1, the calculation just returns -1 * When --layout is -2, the calculation is lower than -1 */ --layout-span: calc((var(--aside) * var(--layout)) + var(--aside) - 1); /** * Calculate the maximum index of the last column (the one "before" the aside) */ --max-span: calc(-1 * var(--aside) - 1); /** * get the max between --layout-span and the latest column index. * -1 means full width * --max-span means default layout */ --span: max(var(--max-span), var(--span)); grid-column-start: 1; grid-column-end: var(--span); }
  • Посмотреть вживую можно здесь →

И наоборот, когда небольшая группа студентов изучает текст у доски, мы могли бы предоставить больше деталей, таких как медиафайлы и триггеры интерактивных действий.

Помимо распознавания лиц

Случаи, с которыми мы столкнулись (), — это всего лишь два примера того, как мы можем использовать технологию распознавания лиц для верстки или типографских областей. Tensorflow предоставляет другие модели и библиотеки, которые могут преобразовывать поток с камеры в переменные для наших страниц. Кроме того, мы не должны забывать, что в наших смартфонах есть много других датчиков, которые мы могли бы использовать с помощью API датчиков: GPS, акселерометр, окружающий свет и т. д.

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

В течение многих лет мы привыкли использовать запросы CSS Media для адаптивного веб-дизайна. Однако размер области просмотра — это только одна из переменных взаимодействия с пользователем. Недавно в браузеры попал новый тип медиа-запроса, разработанный с учетом пользовательских предпочтений, например, prefers-color-scheme и prefers-reduced-motion . Это дает дизайнерам и разработчикам возможность сделать шаг вперед в практике веб-дизайна, позволяя веб-странице адаптироваться ко всей среде, а не только к устройству пользователя. В эпоху больших данных у нас есть возможность выйти за рамки отзывчивого и адаптивного дизайна. Наши веб-страницы, наконец, могут «покинуть экран» и стать частью глобального опыта пользователя. Интерактивный дизайн будет включать в себя все эти возможности, поэтому продолжение экспериментов с возможными комбинациями технологий и веб-дизайна будет иметь решающее значение в последующие годы.