Cum să utilizați mișcarea feței pentru a interacționa cu tipografia

Publicat: 2022-03-10
Rezumat rapid ↬ În acest articol, vom aborda cum să combinați Machine Learning, fonturi variabile și grile CSS pentru a crea machete care să răspundă la proximitatea, înclinarea și numărul fețelor utilizatorilor.

Designerii web caută mereu noi modalități de a îmbunătăți prezentarea conținutului unei pagini. Uneori, acest lucru poate duce la soluții ingenioase sau la interacțiunea cu tehnologii care sunt adesea ținute departe de domeniul designului. În acest articol vom aduce tipografia în contact cu Inteligența Artificială, folosind învățarea automată pentru a detecta lucruri precum proximitatea feței utilizatorului pentru a îmbunătăți lizibilitatea textului.

Vom experimenta cum să folosim recunoașterea feței cu Tensorflow pentru a extrage unele informații din cameră, cum ar fi distanța dintre ecran și fața utilizatorului sau numărul de persoane care citesc pagina. Apoi, vom transmite acele date către CSS pentru a adapta tipografia și pentru a ajusta aspectul paginii.

Ce este Tensorflow?

Tensorflow este o platformă open-source de la Google pentru Machine Learning. Învățarea automată este un domeniu al informaticii care studiază algoritmii care învață să recunoască relații complexe și modele recurente din imagini, piste audio, serii temporale, text natural și date în general. Acești algoritmi generează modele matematice (numite și modele antrenate), care sunt un fel de schemă care poate fi folosită pentru a lua decizii pe baza datelor de intrare. Dacă doriți să abordați subiectul, Charlie Gerard a scris despre ML pentru dezvoltatorii frontend aici pe Smashing Mag.

Tensorflow oferă o mulțime de instrumente pentru dezvoltatorii AI, oamenii de știință de date, matematicienii, dar nu vă panicați dacă analiza datelor nu este pâinea voastră zilnică! Vestea bună este că nu trebuie să fii un expert pentru a-l folosi, atâta timp cât folosești modele prefabricate, așa cum vom face noi.

Modelele Tensorflow sunt disponibile pentru a fi utilizate pe web cu SDK-ul lor JavaScript.

Înființat

Pentru a începe să folosim algoritmi de recunoaștere a feței, trebuie să urmăm câțiva pași:

  • încărcați SDK-ul Tensorflow.
  • încărcați biblioteca Facemesh care conține modelul matematic.
  • accesați camera utilizatorului și transmiteți-o în flux către un element video HTML. Facemesh va analiza cadrele din eticheta video pentru a detecta prezența fețelor.

În aceste proiecte vom folosi Tensorflow prin CDN, dar este disponibil și pe NPM dacă preferați modul bundler:

 <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 nu face truc în sine, așa că trebuie să adăugăm Facemesh, o bibliotecă care este construită pe partea de sus a cadrului ML și oferă un model deja antrenat pentru recunoașterea feței:

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

Următorul pas este să configurați biblioteca Facemesh pentru a încărca modelul antrenat și pentru a defini funcția care va evalua datele feței dintr-un flux video:

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

Acum suntem gata să cerem utilizatorului permisiunea de a accesa fluxul camerei sale folosind o etichetă video:

 // 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 va solicita permisiunea și va începe să transmită în flux camera în elementul video. Odată acceptată, camera va începe să fie transmisă în flux către eticheta video, în timp ce consola browserului va înregistra informațiile feței detectate de Facemesh.

Vă rugăm să rețineți că permisiunile camerei necesită o conexiune https securizată sau localhost: nu puteți deschide pur și simplu fișierul index.html. Dacă nu sunteți sigur cum să configurați un server local de verificare http-server pentru Node sau urmați acest ghid pentru Python sau acesta pentru PHP.

Mai multe după săritură! Continuați să citiți mai jos ↓

Cazul 1. Reglați tipografia utilizând camera smartphone-ului

Navigam pe web peste tot cu smartphone-ul nostru. A fost o vreme, nu cu mult timp în urmă, în care luam trenuri sau autobuze aglomerate și țineam smartphone-ul foarte aproape de ochi pentru că nu era spațiu. În multe momente și locuri ale zilei noastre, schimbăm adesea poziția și înclinarea smartphone-ului, chiar dacă urmărim același site. Distanța dintre ochi și smartphone ne afectează capacitățile de citire. Evaluând această distanță, putem ajusta microtipografia pentru a optimiza glifele pentru o citire mai apropiată sau mai îndepărtată.

Detectarea feței înseamnă, desigur, și detectarea poziției ochilor. Putem folosi datele furnizate de Facemesh pentru a calcula dimensiunea feței noastre în raport cu întreaga imagine capturată de cameră. Putem presupune că, cu cât fața noastră este mai mare, cu atât suntem mai aproape de ecran. Putem configura o scară de la 0 (un braț distanță unul de celălalt - fața ocupă aproximativ jumătate din cameră) la 1 (lipit de ecran) și detectam valoarea curentă cu o diviziune de segmente:

 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); }
Reprezentarea feței utilizatorului pe segmente este plasată în cadrul unui smartphone pentru a indica câtă zonă a ecranului este ocupată de față.
Două exemple de trăsături detectate de Facemesh, cum ar fi poziția și înclinarea ochilor, a nasului și a gurii. Putem folosi zona dintre puncte pentru a calcula apropierea de camera smartphone-ului. (Previzualizare mare)

Acum că am calculat ratio , este timpul să facem ceva magie, trecând valoarea în foaia de stil:

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

Cu această valoare și un pic de calcul, am putea aplica cu ușurință mici modificări la greutatea fontului, dimensiunea și poate și stilul, dar putem face ceva și mai bun. Folosind un font variabil, un font care are forme și spații parametrizate ale glifelor, putem ajusta percepția fiecărui glif prin actualizarea variației de dimensiune optică a acestuia.

Deoarece fiecare font variabil folosește propria sa scară pentru valorile dimensiunii optice, trebuie să relaționăm valoarea raportului cu acea scară. În plus, este posibil să dorim să ne mutăm doar între un subset de dimensiuni optice disponibile, pentru a oferi doar mici îmbunătățiri.

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

O poți vedea live aici. Vă rugăm să rețineți că acest exemplu este doar o demonstrație a modului în care funcționează tehnologia. Modificările tipografice ar trebui să fie aproape imperceptibile pentru ochii utilizatorului pentru a oferi cu adevărat o experiență mai bună pentru cititor. Aici am folosit forme de glife, dar folosirea culorilor pentru a crește sau a reduce contrastele este doar o altă soluție bună de încercat. Un alt experiment a fost detectarea unghiului feței pentru a calcula perspectiva citirii, modificând ascendenții, descendenții și înălțimea literelor:

Vezi stiloul [Facemesh și ascenders/descenders](https://codepen.io/smashingmag/pen/oNxrYop) de Edoardo Cavazza.

Vedeți Pen Facemesh și ascenders/descenders de Edoardo Cavazza.

Cazul #2: Ajustarea unui aspect atunci când numărul de persoane care caută se schimbă

În acest al doilea caz, vom schimba aspectul pe baza numărului de persoane care urmăresc ecranul. Ne putem imagina un eseu afișat pe tabla interactivă în contextul unei clase de liceu. Acest scenariu este liniștit diferit de cel detectat de interogarea media de proiecție învechită, deoarece dorim să ajustam aspectul paginii dacă numărul de elevi care vizionează este mai mic sau mai mare decât cei 10. Când doar câțiva elevi sunt în clasă, ei putem aborda în siguranță tabla, dar dacă întreaga clasă este prezentă, probabil că spațiul nu este suficient și trebuie să schimbăm aspectul pentru a afișa mai puține (și mai mari) lucruri.

Avem nevoie doar de câteva modificări la scriptul anterior pentru a detecta corect numărul de fețe care se uită la tablă. Mai întâi, trebuie să îi instruim pe Facemesh să detecteze mai multe fețe:

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

Și apoi, trebuie să trecem acel număr în foaia de stil:

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

Din nou, am putea folosi această valoare pentru a crește pur și simplu dimensiunea fontului, dar scopul nostru este să oferim un aspect complet diferit. Aspectele de grilă CSS ne pot ajuta în această misiune. Acest document proiectat este o formă lungă cu o parte care conține imagini aferente:

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

Și acesta este aspectul său implicit:

 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; }
Stânga: când vizionează mai mult de 10 persoane, prioritizează textul principal folosind toate coloanele disponibile și mutând imaginile după text. Dreapta: un aspect de pagină care utilizează 12 coloane cu ghiduri active pentru inspectorii de grilă Firefox. Toate cele 12 coloane sunt folosite pentru textul principal, 4 pentru imaginile de după acesta.
Stânga : aspectul implicit al paginii folosește 8 din 12 coloane pentru textul lung și restul de 4 pentru imagini. Dreapta : Când vizionează mai mult de 10 persoane, acordăm prioritate textului principal folosind toate coloanele disponibile și mutând imaginile după text. (Previzualizare mare)

Atunci când un număr mare de oameni urmăresc, trebuie să privilegiăm contextul de citire lung, oferind mai mult spațiu coloanei principale, mărind dimensiunea fontului și eliminând elementele deranjante. Pentru a face acest lucru, creștem numărul de coloane extinse, mutând deoparte sub textul principal.

 :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); }
  • Îl puteți vedea live aici →

Viceversa, atunci când un grup mic de studenți experimentează textul lângă tablă, am putea oferi mai multe detalii, cum ar fi fișiere media și declanșatoare de acțiuni interactive.

Dincolo de recunoașterea feței

Cazurile cu care ne-am confruntat () sunt doar două exemple ale modului în care putem folosi tehnologia de recunoaștere a feței pentru aspect sau domenii tipografice. Tensorflow oferă alte modele și biblioteci care pot transforma fluxul camerei în variabile pentru paginile noastre. Mai mult, nu trebuie să uităm că în smartphone-urile noastre există o mulțime de alți senzori pe care i-am putea exploata folosind API-urile senzorilor: GPS, accelerometru, lumină ambientală etc.

Deoarece starea de spirit influențează modul în care citim, studiem și căutăm informații, prin învățarea automată putem analiza și expresiile utilizatorului pentru a trece de la aspecte minime la cele detaliate, în funcție de spiritul utilizatorului.

De mulți ani am fost obișnuiți să folosim interogări CSS Media pentru design web responsive. Cu toate acestea, dimensiunea ferestrei de vizualizare este doar una dintre variabilele experienței utilizatorului. Recent, un nou tip de interogare media menit să respecte preferințele utilizatorilor a aterizat browserele, cum ar fi prefers-color-scheme și prefers-reduced-motion . Acest lucru oferă designerilor și dezvoltatorilor o modalitate de a face un pas înainte în practicile de design web, permițând paginii web să se adapteze întregului mediu în loc de doar dispozitivul utilizatorului. În era datelor mari, avem oportunitatea de a merge dincolo de designul receptiv și adaptiv. Paginile noastre web pot „părăsi ecranul” și devin parte din experiența globală a utilizatorului. Designul de interacțiune va implica toate aceste posibilități, așa că continuarea experimentării cu posibilele combinații dintre tehnologie și web design va fi crucială în următorii ani.