Projekt augmented reality, trackování a identifikace obličeje ve webovém prohlížeči

Členové projektu

Jakub Ferenc, Studia nových médií, e-mail: jakubferenc1911@gmail.com

Motivace vzniku projektu a jeho význam

Snímání pohybu hlavy, identifikace obličeje v real-time video datech a na nich založené interakce jsou dnes již běžně viditelné v nativních aplikacích nejen mobilních platforem jako jsou Android, Windows Phone či Apple iOS. Taková řešení mají smysl, neboť nativní aplikace poskytují programátorovi jednak stabilní, odzkoušené aplikační rozhraní, které může využít pro svůj projekt, jednak také dostatečný výkon zajišťující plynulý chod.

Přesně tyto vlastnosti nativních řešení chybí tvůrci, který si pro svůj projekt vybral webovou platformu: moderní aplikačních rozhraní, tak jak je definuje webové konsorcium W3C, jsou jen zřídkakdy plně implementována dodavateli webových prohlížečů; někdy naopak rychlé přijetí nových funkcionalit má za následek, že takový prohlížeč sice funkci podporuje, ale jelikož je API pod vedením W3C stále vyvíjeno, hrozí, že se API změní nebo zcela zavrhne ve prospěch jiného řešení. Zmiňme také, že webová platforma se zatím také nemůže nativním řešením rovnat v plynulosti a rychlosti. To jsou tedy jen některá omezení, se kterými se vývojář pro webovou platformu setkává, pokud chce navrhovat interakce s netradičními vstupními zařízeními jako je web kamera a pohyb hlavy.

Ale jelikož experimentování v nestabilních a neprozkoumaných vodách je jádrem hackerství, rozhodl jsem se pro svůj projekt vytěžit co nejvíce z moderních aplikačních rozhraní a funkcionalit současné webové platformy. Konkrétně to znamenalo vytvořit webovou aplikaci, která by v datovém streamu z webkamery (nebo obecně kamery zařízení) našla obličej, tento obličej pak na základě databáze fotografií s určitou pravděpodobností identifikovala, a nakonec u hlavy správně identifikovaného obličeje zobrazila 3D objekt, který by real-time následoval pozici hlavy.

K vedlejší, přesto přítomné motivaci ke tvorbě svého projektu mohu dodat stav aktuálního vývoje virtuální a rozšířené reality jako nadcházejícího dominantního paradigmatu počítačových interakcí. Přestože se s VR (virtual reality) a AG (augmented reality) dnes setkáváme především v průmyslu počítačových her, designové patterny i teoretický výzkum na nich založený se může lehce aplikovat pro tvorbu nových uživatelských zážitků (user experiences) i v jiných, komerčních doménách jako je např. sektor služeb.

Tvůrci webů by tyto nová paradigmata interakcí a digitálního designu měli taktéž přijmout a využívat. A to nejen v experimentálních prototypech. Webová platforma tu s námi ještě nějakou dobu bude. Spíše než její zánik lze v blízké době předpokládat její metamorfózu do platformy využívající dosavadní technologickou infrastrukturu (nebo její budoucí vylepšení), ale poskytující (právě díky integraci VR a AG) zcela nové zážitky. Navrhovat pro AG a VR znamená pro (web) designéry výzvu, neboť kromě přizpůsobení kreativní exprese je třeba seznámení s novým médiem, neboli kreativním materiálem. Materiálem, jímž je technologie, konkrétněji software.

Jakožto web designér s funkční znalostí javascriptu jsem tento projekt pojmul právě jako první seznámení s materiálem pro tvorbu VR/AG.

Použitý materiál a software

Hardware

  • Desktop či notebook s webkamerou
  • Mobilní zařízení s kamerou a operačním systémem Android
  • Dodatečně Google Carboard při zapnutém stereo obrazu


Software

  • Google Chrome (s podporou WebGL a datového streamu z webkamery)
  • THREE.js
  • Headtrackr.js
  • Účet zdarma na Mashape + Lamdal API (pro identifikaci obličeje)

Popis vývoje a konečné verze vlastního produktu

Koncept

Koncept projektu se vyvíjel postupně. Již od začátku jsem věděl, že se zaměřím na webovou platformu a VR nebo AG. První nápadem bylo si vyzkoušet a případně rozšířit tutoriál z webu sitepoint.com[1], který kombinuje moderní webové technologie, populární Google Cardboard pro aplikování virtuální reality za pomoci těchto 3D brýlí od Google a mobilního telefonu, který, vložený před čočkami brýlí, generuje obraz ve stereo efektu, a nakonec WebGL webové grafiky. Hlavním konceptem tutoriálu bylo vytvořit VR prostředí, kde zářicí bubliny generované ve WebGL budou měnit svůj vzhled v závislosti na počasí na zvolených místech světa.

Tento nápad jsem nakonec zavrhl, neboť jsem měl v plánu pracovat nejen s virtuální realitou, ale také s realitou rozšířenou. V ideálním případě jsem chtěl, aby projekt obsahoval oba prvky. Proto mě zaujal další tutoriál[2], který tyto prvky kombinoval, avšak celkový koncept spočíval “pouze” v tom, že datový stream z videokamery bude filtrován skrze vlastní filtr, jež by měly manipulovat s atributy jednotlivých pixelů obrazů tak, aby se dosáhl zajímavého filtru-efektu. I tento nápad jsem zavrhl.

Výsledek této průzkumné práce ale nebyl nulový. Studium podkladů pro tutoriály mi pomohlo získat lepší přehled nejen o tom, co je na webové platformě možné, ale také jsem pochopil, jak jednotlivé VR/AG prvky konkrétně implementovat v javascript kódu. S těmito nově nabytými znalostmi se mi mnohem lépe přemýšlelo o vlastním konceptu projektu.

Ten byl následující: z datového videostreamu webová aplikace rozpozná obličej, který následně identifikuje na základě porovnání daného obličeje s předpřipravenou databází fotografií. Pokud se osoba nachází v databázi, skládající se z fotek studentů či vyučujících oboru SNM, webová aplikace zobrazí jméno rozpoznané osoby, u jejíž hlavy zobrazí levitující 3D element, konkrétně krychli otexturovanou logem oboru SNM. Jednoduše řečeno, cílem webové aplikace je rozpoznat podle obličeje, zda daná osoba je součástí Studia nových médií.

Tento vlastní koncept od začátku počítal s tím, že bude používán s brýlemi Google Cardboard, jak ale ukáži dále, od takového řešení jsem ustoupil, jelikož příliš snižoval výkon a responzivitu (ve smyslu odezvy, nikoli adaptace) webu. Je potřeba říci, že stereo efektu lze dosáhnout několika řádky kódu, tudíž se jedná spíše o „sugar code“, nežli nepostradatelnou část konceptu. I když v konečné verzi projektu se stereo efektem nepracuji, jeho zapnutí je nenáročné, a tak neuškodí, pokud v části, o implementaci zmíním, jak stereo efekt (pro Google Cardboard a jiná řešení VR) pro případné zájemce zapnout.

Schematické zobrazení konceptu

Soubor:Schematické zobrazení
Schematické zobrazení

Vrni project desc.png

Implementace

Příprava

Protože tvoříme webovou stránku, můžeme celou aplikaci napsat v jediném HTML souboru, kde se budou nacházet všechny HTML, CSS a Javascript kódy. Pro přehlednost a budoucí úpravy je zřejmě vhodnější již od začátku kódy od sebe oddělit do samostatných souborů. Pro vytvoření WebGL grafiky, trackování obličeje a identifikaci je třeba stáhnout a do HTML souboru přilinkovat knihovny THREE.js, headtrackr.js a založit si účet zdarma na „tržišti“ aplikačních rozhraní Mashape, konkrétně Face Recognition and Face Detection API od Lambda Labs. Po registraci uživatel získá privátní API klíče, které mu umožní ze své aplikace zasílat na API dotazy a získávat pro další zpracování odpovědi.

Části aplikace

THREE.js scéna, kamera, světlo a renderer

Všechny důležité zobrazované části aplikace jsou vnořené do THREE.js objektu renderer. Jak už název napovídá, tento objekt obstarává renderování, tedy vyobrazení aplikace a pomocí nativní grafické knihovny pro web WebGL. Renderer si představme jako 3D svět, který obsahuje 3D objekty, 2D objekty ale i speciální objekty typu scene, light, camera, které definují kde a jak se nám ostatní objekty budou zobrazovat. Objekt scene je konkrétní „plátno“, na které budeme objekty (tedy i například video z kamery) přidávat. Důvod pro použití THREE.js je ten, že poskytuje při srovnání s čistým psaním WebGL kódu uživatelsky přívětivější způsob vytváření WebGL projektů. Druhým důvodem zmiňme možnost velice jednoduše přizpůsobit aplikaci pro Google Cardboard díky tomu, že všechny viditelné části aplikaci náleží jedinému objektu renderer, tudíž pro tvorbu stereo obrazu stačí provést úpravy právě na tomto objektu.

Video z kamery

Pro získání surového video streamu aplikace využívá WebRTC API, jež zajišťuje v moderních prohlížečích komunikaci v reálném čase. V tomto projektu WebRTC API předává data z kamery zařízení do HTML5 elementu <video>, který data standardně zobrazuje, ale v tomto případě HTML element <video> není nikdy přidán do HTML dokumentu; existuje pouze v Javascript kódu pro předání video streamu dalším funkcím ke zpracování.

Canvas pro vytvoření obrázku z video streamu

Pro identifikace obličeje osoby na videu je třeba vytvořit bitmapový obrázek, který bude porovnáván s předpřipravenou databází obličejů. Pro tento účel si vytvářím opět pouze v Javascript kódu pomocný HTML element <canvas>, standardně sloužící pro vykreslování 2D grafiky, neboť poskytuje jednoduchou metodu vytváření bitmapy z video streamu.

Obdélník pro trackování obličeje

Pro vizuální nápovědu toho, jak aplikace snímá obličej z video streamu, jsem implementoval jednoduchý obdélník, který s pomocí dat dodávaných z výpočtů knihovny headtrackr.js sleduje pohyb halvy snímané osoby.

THREE.js 3D kostka

Pro prvek rozšířené reality projekt obsahuje 3D kostku otexturovanou logem oboru SNM. Kostka není statická, ale v reálném čase reaguje na pohyb hlavy osoby snímané kamerou, a tak vytváří dojem, že kostka označuje, zda je osoba součástí oboru SNM.

Tvorba rendereru

Kód ověřuje, zda prohlížeč podporuje WebGL. Pro ověření používám malou knihovnu Detector.js, ale existuje mnoho jiných způsobů, jak podporu určitých Javascript API prohlížeče otestovat. Pokud prohlížeč WebGL podporuje, bude se renderovat WebGL, pokud ne, THREE.js využije experimentální alternativy, kterou se snaží zobrazit scénu bez WebGL. Objekt renderer nakonec přidáme do DOM HTML stránky.

    if (Detector.webgl) {
        renderer = new THREE.WebGLRenderer({
            antialias: true
        });
    } else {
        renderer = new THREE.CanvasRenderer();
    }
    container = document.getElementById("webglcanvas");
    container.appendChild(renderer.domElement);

Tvorba scény, světla, kamery

Zde jsou definovány parametry kamery a světla scény. Kamera a světlo jsou pak přidány do scény.

    scene = new THREE.Scene();

    camera = new THREE.PerspectiveCamera(90, 1, 0.001, 800);
    camera.position.set(0, 0, 12);
    camera.lookAt(scene.position);
    scene.add(camera);

    pointLight = new THREE.PointLight( 0xffffff, 1, 100 );
    pointLight.position.set( 5, 10, 20 );

    scene.add(pointLight);  

Práce s video streamem z kamery zařízení

Jelikož je přístup ke streamu multimediálních zařízení implementován ve webových prohlížečích zatím různě, je třeba se ujistit, že budeme mít přístup aspoň k jedné z implementací:

navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;


Pokud je globální objekt MediaStreamTrack, obsahující seznam všech dostupných multimediálních streamů, přítomen, nalezneme identifikátor námi požadovaného video streamu, tedy web kamery, konkrétně té na zadní straně zařízení :

        MediaStreamTrack.getSources(function (sources) {

            for (var i = 0; i < sources.length; ++i) {
                var source = sources[i];
                if (source.kind === 'video') {
                    if (source.facing && source.facing == "environment") {
                        options.video.optional.push({
                            'sourceId': source.id
                        });
                    }
                }
            }

Máme-li identifikátor video streamu, voláme funkci navigator.getUserMedia(options, streamFound, streamError), které předáváme identifikátor a také callback funkci streamFound, kde dále zpracováváme video stream:

navigator.getUserMedia(options, streamFound, streamError);

V callback funkci streamFound() si především připravujeme objekty pro pozdější použití. Výjimkou je HTML5 element <video>, kterému do parametru zdroje dat přidáme proměnnou stream, jež je povinným parametrem callback funkce, a video (bez přidání do DOM) spustíme:

    video.src = URL.createObjectURL(stream);
    video.play();

Připravovanými objekty jsou tři pomocné <canvas> elementy: na prvním vykreslíme video stream a přidáme do scény na WebGL renderer, druhý slouží jako dočasné místo, kde si budeme odkládat framy (snímky) z video streamu a vytvářet z nich bitmapové obrázky, které budeme zasílat na vzdálený server pro identifikaci obličeje, navíc potřebujeme pomocný <canvas>, jenž vyžaduje knihovna headtrackr.js. Dále si připravíme 3D kostku následujícím kódem:

var snmCubeMaterial = new THREE.MeshPhongMaterial( { map: new THREE.ImageUtils.loadTexture( 'img/logo_original.png' ) } );
        var geometry = new THREE.BoxGeometry(3, 3, 3, 4, 4, 4);
        var material = new THREE.MeshLambertMaterial({
            color: 0xFFFFFF
            , transparent: true
            , opacity: .8
            , overdraw: .5
            , wireframe: false
        });
cube = new THREE.Mesh(geometry, snmCubeMaterial); 

Nakonec voláme funkci faceTrackingInit(), která inicializuje trackování obličeje.

Trackování obličeje

Zde pouze voláme konstruktor knihovny headtrackr.js s parametry zapínající počítání pozice a úhlu natočení hlavy snímané osoby. V parametrech funkce init zadáváme <video> HTML element, ze kterého si knihovna sama načítá video stream a pomocný <canvas> HTML element, který knihovna používá pro interní výpočty pozice hlavy a obličeje.

    var htracker = new headtrackr.Tracker({
        ui: false
        , headPosition: true
        , calcAngles: true
    });
    htracker.init(video, canvasTemp, false);
    htracker.start();

Knihovna headtrackr.js exponuje v dokumentu události, jež aktualizují stav trackování objektů ve videu (obličej nalezen / ztracen / vyhledávám) a po nalezení také jeho pozice na osách x, y, z. Událostmi, které zachytáváme, jsou: facetrackingEvent, headtrackingEvent a headtrackrStatus. Je nutno poznamenat, že ve funkcích zpracovávající události facetrackingEvent a headtrackingEvent nic nezobrazujeme, pouze si do globálních proměnných ukládáme z těchto událostí informace, které kontrolujeme v jiné funkci volané periodicky (60 za vteřinu) funkcí requestAnimationFrame. S událostí headtrackrStatus ale již pracujeme, neboť ve chvíli, kdy knihovna nalezla ve videu obličej, vytváříme z videa zmiňovaný bitmapový obrázek a zásíláme jej na vzdálené API k identifikaci.

Identifikace obličeje

Jak už bylo dříve řečeno, pro identifikaci obličeje aplikace využívá externí webové služby. Abychom mohli tuto službu využívat přes její API z naší aplikace, je třeba si na adrese https://market.mashape.com/lambda/face-recognition-and-face-detection/ vytvořit účet pro získání tzv. X-Mashape-Key, což je řetězec znaků, kterým při každém volání API budeme identifikovat náš uživatelský účet.

Na obrázku je možno vidět administrační rozhraní na mashape.com: Bez-názvu-1.png

Povšimněme si nabídky “Album Management” vlevo nahoře. Přímo přes toto administrační rozhraní si vytvoříme album, jehož jméno a identifikátor si zapamatujeme, neboť jej budeme dále využívat. Po vytvoření nahrajeme do alba v záložce Train album fotografie, které označíme identifikátorem “entryid”, což pro naší aplikaci bude jméno osoby na zvolené fotografii. Po přidání fotografií osob klikneme na záložku Rebuild album, čímž spustíme analýzu fotografií. Identifikace obličeje je funkční i s několika fotografiemi, ale pro přesnější výsledky je vhodné přidat fotografií více. Máme-li na serveru služby pro identifikaci obličeje vše připravené, můžeme zkusit na server zaslat fotografii a získat výsledek.

Pro tvorbu fotografie z video streamu, její zaslání na vzdálený server a získání výsledku uvádím zkrácený kód.

Video stream z elementu <video> zapíšeme do pomocného <canvas> elementu (stačí nám nižší rozlišení než je skutečné rozlišení video streamu, např. 640x480px), využijeme nativní metody canvasu pro převod jeho obsahu na URI reprezentaci, kterou převedeme do Blobu, surových binárních dat, jež můžeme poslat jako soubor ve formuláři:

        canvasSnapshotContext.drawImage(video, 0, 0, 640, 480);

        var URI = canvasSnapshot.toDataURL();
        var file = dataURItoBlob(URI);

Připravíme si formulářová data tak, jak vyžaduje API pro identifikaci:

        var fd = new FormData();
       
        fd.append("files", file);
        fd.append("album", "stunome_vrni");
        fd.append("albumkey", "183a13952adbd5d998aaca63efc100f6b0ab7f82b861dcc7293e86cb161f8a02");

Odešleme AJAXový POST požadavek na vzdálené API a z odpovědi získáme položku pole uids na první pozici, což je predikce API s největší pravděpodobností, že se jedná o danou osobu na fotografii:

        $.ajax({
            url: "https://lambda-face-recognition.p.mashape.com/recognize"
            , type: "POST"
            , data: fd
            , processData: false
            , contentType: false
            , beforeSend: function (xhr) {
                xhr.setRequestHeader("X-Mashape-Authorization", "vas_kod");
            }
        }).done(function (result) {

            if (JSON.parse(resultObject).photos[0].tags.length > 0) {

                username = JSON.parse(resultObject).photos[0].tags[0].uids[0].prediction;

            }


        });

Stereo efekt

Pro dosažení stereo efektu stačí pouze vytvořit THREE.js StereoEffect objekt, do jehož konstruktoru jako parametr vložíme již dříve zmíněný renderer objekt. Nastavíme efektu velikost, nejlépe dle velikosti rendereru a zobrazíme efekt voláním metody render nikoli na renderu, ale na proměnné efektu.

   effect = new THREE.StereoEffect(renderer);
   effect.setSize(width, height);
   effect.render(scene, camera);

Zhodnocení

Náplní projektu bylo naprogramovat webovou aplikace, která pomocí kamery zařízení rozpozná a identifikuje osobu a její obličej, podle čehož zobrazí o osobě zvolené informace, včetně 3D prvku rozšířené reality reagujícího v reálném čase na pohyb hlavy.

Jelikož tyto funkcionality byly implementovány ve webovém prohlížeči, mnoho mobilních zařízení bude mít výkonnostní problémy aplikaci plynule zobrazit. Z tohoto důvodu je zřejmé, že pro skutečnou realizaci zvoleného konceptu bude do budoucna vhodnější využít nativních platforem zařízení.

Nic to nemění na faktu, že jsem díky tomuto projektu prozkoumal moderní zákoutí webové platformy, především práci s video streamem, WebGL grafikou a kombinací obojího pro tvorbu rozšířené reality. Tyto znalosti jsou přenosné a budou se hodit pro další nejen experimentální projekty.

Ukázka / Zdrojové soubory


Videodokumentace

Vrni project video intro.png

Odkaz na video

Seznam zdrojů

  1. PATRICK, Catanzariti. Bringing VR to the Web with Google Cardboard and Three.js. 2015. Dostupné také z: https://www.sitepoint.com/bringing-vr-to-web-google-cardboard-three-js
  2. PATRICK, Catanzariti. Filtering Reality with JavaScript and Google Cardboard. 2015. Dostupné také z: [https://www.sitepoint.com/filtering-reality-with-javascript-google-cardboard/]