Jak używać ruchu twarzy do interakcji z typografią

Opublikowany: 2022-03-10
Krótkie podsumowanie ↬ W tym artykule omówimy, jak łączyć uczenie maszynowe, zmienne czcionki i siatki CSS, aby tworzyć układy, które reagują na bliskość, nachylenie i liczbę twarzy użytkowników.

Projektanci stron internetowych zawsze szukają nowych sposobów na ulepszenie prezentacji zawartości strony. Czasami może to prowadzić do pomysłowych rozwiązań lub interakcji z technologiami, które często są trzymane z dala od dziedziny projektowania. W tym artykule połączymy typografię ze sztuczną inteligencją, wykorzystując uczenie maszynowe do wykrywania takich rzeczy jak bliskość twarzy użytkownika w celu poprawy czytelności tekstu.

Poeksperymentujemy, jak korzystać z rozpoznawania twarzy za pomocą Tensorflow, aby wydobyć z kamery pewne informacje, takie jak odległość między ekranem a twarzą użytkownika czy liczba osób czytających stronę. Następnie przekażemy te dane do CSS w celu dostosowania typografii i dostosowania układu strony.

Co to jest Tensorflow?

Tensorflow to platforma typu open source firmy Google do uczenia maszynowego. Uczenie maszynowe to dziedzina informatyki, która bada algorytmy, które uczą się rozpoznawać złożone relacje i powtarzające się wzorce z obrazów, ścieżek dźwiękowych, szeregów czasowych, tekstu naturalnego i ogólnie danych. Algorytmy te generują modele matematyczne (zwane również modelami wyszkolonymi), które są rodzajem schematu, który można wykorzystać do podejmowania decyzji na podstawie danych wejściowych. Jeśli chcesz podejść do tematu, Charlie Gerard napisał o ML dla programistów frontend tutaj na Smashing Mag.

Tensorflow zapewnia wiele narzędzi dla programistów AI, analityków danych, matematyków, ale nie panikuj, jeśli analiza danych nie jest Twoim chlebem powszednim! Dobrą wiadomością jest to, że nie musisz być ekspertem, aby z niego korzystać, o ile korzystasz z gotowych modeli, tak jak my.

Modele Tensorflow są dostępne do użycia w sieci Web z ich pakietem JavaScript SDK.

Organizować coś

Aby zacząć korzystać z algorytmów rozpoznawania twarzy, musimy wykonać kilka kroków:

  • załaduj pakiet SDK Tensorflow.
  • załaduj bibliotekę Facemesh, która zawiera model matematyczny.
  • uzyskać dostęp do kamery użytkownika i przesłać ją strumieniowo do elementu wideo HTML. Facemesh przeanalizuje klatki z tagu wideo, aby wykryć obecność twarzy.

W tych projektach zamierzamy używać Tensorflow przez CDN, ale jest on również dostępny na NPM, jeśli wolisz pakietowy sposób:

 <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 sam w sobie nie załatwia sprawy, więc musimy dodać Facemesh, bibliotekę zbudowaną na szczycie frameworka ML i dostarczającą już wytrenowany model rozpoznawania twarzy:

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

Następnym krokiem jest skonfigurowanie biblioteki Facemesh w celu załadowania wytrenowanego modelu i zdefiniowanie funkcji, która będzie oceniać dane twarzy ze strumienia wideo:

 // 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); }

Teraz jesteśmy gotowi poprosić użytkownika o pozwolenie na dostęp do strumienia kamery za pomocą tagu wideo:

 // 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();

Metoda navigator.mediaDevices.getUserMedia wyświetli monit o pozwolenie i rozpocznie przesyłanie strumieniowe kamery do elementu wideo. Po zaakceptowaniu kamera zacznie przesyłać strumieniowo do tagu wideo, podczas gdy konsola przeglądarki będzie rejestrować informacje o twarzy wykryte przez Facemesh.

Należy pamiętać, że uprawnienia kamery wymagają bezpiecznego połączenia https lub hosta lokalnego: nie można po prostu otworzyć pliku index.html. Jeśli nie jesteś pewien, jak skonfigurować lokalny serwer http-server checkout dla Node lub postępuj zgodnie z tym przewodnikiem dla Pythona lub tym dla PHP.

Więcej po skoku! Kontynuuj czytanie poniżej ↓

Przypadek 1. Dostosuj typografię za pomocą aparatu w smartfonie

Wszędzie poruszamy się po sieci za pomocą naszego smartfona. Był czas, nie tak dawno temu, kiedy jeździliśmy zatłoczonymi pociągami lub autobusami i trzymaliśmy smartfona bardzo blisko oczu, bo nie było miejsca. W wielu momentach i miejscach naszych czasów często zmieniamy położenie i nachylenie smartfona, nawet jeśli oglądamy to samo miejsce. Odległość między oczami a smartfonem wpływa na nasze możliwości czytania. Oceniając tę ​​odległość, możemy dostosować mikrotypografię, aby zoptymalizować glify dla bliższego lub dalszego czytania.

Wykrywanie twarzy oznacza oczywiście również wykrywanie pozycji oczu. Na podstawie danych dostarczonych przez Facemesh możemy obliczyć wielkość naszej twarzy w stosunku do całego zdjęcia uchwyconego przez kamerę. Możemy założyć, że im większa jest nasza twarz, tym bliżej ekranu jesteśmy. Możemy ustawić skalę od 0 (jedno ramię oddalone od siebie — twarz zajmuje mniej więcej połowę aparatu) do 1 (przyklejona do ekranu) i wykrywać aktualną wartość z podziałem na segmenty:

 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); }
Reprezentacja twarzy użytkownika za pomocą segmentów jest umieszczona wewnątrz ramki smartfona, aby wskazać, ile obszaru ekranu zajmuje twarz.
Dwa przykłady cech wykrytych przez Facemesh, takie jak pozycja i nachylenie oczu, nosa i ust. Obszar między punktami możemy wykorzystać do obliczenia odległości do aparatu w smartfonie. (duży podgląd)

Teraz, gdy obliczyliśmy ratio , nadszedł czas, aby zrobić trochę magii, przekazując wartość do arkusza stylów:

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

Przy tej wartości i odrobinie kalkulacji moglibyśmy łatwo wprowadzić niewielkie zmiany w grubości, rozmiarze i być może stylu czcionki, ale możemy zrobić coś jeszcze lepszego. Korzystając ze zmiennej czcionki, która ma sparametryzowane kształty i odstępy glifów, możemy dostosować postrzeganie każdego glifu, aktualizując jego wariację rozmiaru optycznego.

Ponieważ każda czcionka zmienna używa własnej skali dla wartości rozmiaru optycznego, musimy powiązać naszą wartość współczynnika z tą skalą. Co więcej, możemy chcieć poruszać się tylko między podzbiorem dostępnych rozmiarów optycznych, aby zapewnić tylko niewielkie ulepszenia.

 .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); }

Możesz to zobaczyć na żywo tutaj. Należy pamiętać, że ten przykład to tylko demonstracja działania tej technologii. Zmiany typograficzne powinny być prawie niezauważalne dla oczu użytkownika, aby naprawdę zapewnić lepsze wrażenia czytelnika. Tutaj wykorzystaliśmy kształty glifów, ale używanie kolorów do zwiększania lub zmniejszania kontrastów to tylko kolejne dobre rozwiązanie do wypróbowania. Kolejnym eksperymentem było wykrycie kąta twarzy w celu obliczenia perspektywy czytania, modyfikowanie wznoszących, zstępujących i wysokości liter:

Zobacz pióro [Facemesh i ascenders/descenders](https://codepen.io/smashingmag/pen/oNxrYop) autorstwa Edoardo Cavazzy.

Zobacz Pen Facemesh i wzloty/zjazdy autorstwa Edoardo Cavazzy.

Przypadek 2: Dostosowywanie układu, gdy zmienia się liczba osób szukających osób

W tym drugim przypadku zmienimy układ na podstawie liczby osób obserwujących ekran. Możemy sobie wyobrazić esej wyświetlany na tablicy interaktywnej w kontekście klasy w szkole średniej. Ten scenariusz różni się nieznacznie od tego wykrytego przez przestarzałe zapytanie o media projekcji, ponieważ chcemy dostosować układ strony, jeśli liczba oglądających uczniów jest mniejsza lub większa niż 10. Gdy w klasie jest tylko kilku uczniów, można spokojnie podejść do tablicy, ale jeśli cała klasa jest obecna, prawdopodobnie miejsca nie wystarczy i musimy zmienić układ, aby pokazać mniej (i większe) rzeczy.

Wystarczy kilka zmian w poprzednim skrypcie, aby poprawnie wykryć liczbę twarzy obserwujących tablicę. Najpierw musimy poinstruować Facemesh, aby wykrył wiele twarzy:

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

A następnie musimy przekazać tę liczbę do arkusza stylów:

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

Ponownie możemy użyć tej wartości, aby po prostu zwiększyć rozmiar czcionki, ale naszym celem jest zapewnienie zupełnie innego układu. Układy CSS mogą nam w tym pomóc. Ten wyświetlany dokument jest długim formularzem z boku, który zawiera powiązane obrazy:

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

A to jest jego domyślny układ:

 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; }
Po lewej: Gdy ogląda więcej niż 10 osób, priorytetowo traktujemy tekst główny, używając wszystkich dostępnych kolumn i przesuwając obrazy za tekstem. Po prawej: układ strony z 12 kolumnami z aktywnymi przewodnikami inspektora siatki Firefoksa. Wszystkie 12 kolumn jest używanych dla tekstu głównego, 4 dla obrazów po nim.
Po lewej : domyślny układ strony wykorzystuje 8 z 12 kolumn na długi tekst, a pozostałe 4 na obrazy. Po prawej : gdy ogląda więcej niż 10 osób, priorytetowo traktujemy tekst główny, używając wszystkich dostępnych kolumn i przesuwając obrazy za tekstem. (duży podgląd)

Gdy ogląda to duża liczba osób, musimy uprzywilejować kontekst czytania w dłuższej formie, dając więcej miejsca na główną kolumnę, zwiększając jej rozmiar czcionki i usuwając przeszkadzające elementy. Aby to zrobić, zwiększamy liczbę łączonych kolumn, przesuwając na bok poniżej głównego tekstu.

 :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); }
  • Możesz to zobaczyć na żywo tutaj →

I odwrotnie, gdy mała grupa uczniów doświadcza tekstu w pobliżu tablicy, moglibyśmy podać więcej szczegółów, takich jak pliki multimedialne i wyzwalacze akcji interaktywnych.

Poza rozpoznawaniem twarzy

Przypadki, z którymi mieliśmy do czynienia (), to tylko dwa przykłady tego, w jaki sposób możemy wykorzystać technologię rozpoznawania twarzy do celów układu lub typograficznych. Tensorflow udostępnia inne modele i biblioteki, które mogą przekształcić strumień kamery w zmienne dla naszych stron. Ponadto nie powinniśmy zapominać, że w naszych smartfonach jest wiele innych czujników, które moglibyśmy wykorzystać za pomocą interfejsów API Sensor: GPS, akcelerometr, światło otoczenia itp.

Ponieważ nastrój wpływa na sposób, w jaki czytamy, studiujemy i szukamy informacji, dzięki uczeniu maszynowemu możemy również analizować wyrażenia użytkownika, aby przełączyć się z minimalnego do szczegółowego układu zgodnie z duchem użytkownika.

Od wielu lat jesteśmy przyzwyczajeni do używania zapytań CSS Media do responsywnego projektowania stron internetowych. Jednak rozmiar widocznego obszaru jest tylko jedną ze zmiennych doświadczenia użytkownika. Ostatnio do przeglądarek trafił nowy rodzaj zapytania o media zaprojektowane z uwzględnieniem preferencji użytkownika, takie jak prefers-color-scheme i prefers-reduced-motion . Daje to projektantom i programistom możliwość zrobienia kroku naprzód w praktykach projektowania stron internetowych, umożliwiając dostosowanie strony internetowej do całego środowiska, a nie tylko do urządzenia użytkownika. W dobie big data mamy możliwość wyjścia poza responsywne i adaptacyjne projektowanie. Nasze strony internetowe mogą wreszcie „opuścić ekran” i stać się częścią globalnego doświadczenia użytkownika. Projektowanie interakcji będzie obejmować wszystkie te możliwości, więc dalsze eksperymentowanie z możliwymi kombinacjami technologii i projektowania stron internetowych będzie kluczowe w nadchodzących latach.