Glimt gjør ett sekund fra hver dag til en film. Det interessante er at du ikke trenger å filme det sekundet: Glimt finner det i videoene du allerede har tatt, og velger sekundet der ditt barn er med i bildet, selv i en full bursdagsvideo med fem andre barn. Alt kjører på iPhone: ingen server, ingen konto, ingen opplasting. Slik fungerer det, med modellene, matematikken og ekte målinger.
Pipelinen
Hvorfor ikke bare bruke Apples Vision?
Vision gjør mye her: det finner ansikter (VNDetectFaceCaptureQualityRequest, som også vurderer hvor skarpt
og hvor rett forfra hvert ansikt er), landemerkene deres (VNDetectFaceLandmarksRequest) og, på iOS 18, hvor bra et bilde
ser ut (CalculateImageAestheticsScoresRequest, som også flagger kvitteringer og skjermbilder). Det det ikke
tilbyr, er hvem et ansikt er. People-albumet i Photos vet det, men den indeksen er ikke åpen for apper.
Den første versjonen av Glimt brukte VNGenerateImageFeaturePrintRequest på et utsnitt av ansiktet. Det er et
generelt bildefingeravtrykk: det sammenligner hår, lys, farger og bakgrunn like mye som selve ansiktet. I praksis
matchet det gladelig søsken, og ethvert barn som var fotografert i samme rom på samme tid av døgnet. Det var feil verktøy.
Modellen for ansiktsgjenkjenning
Nå har Glimt sin egen: SFace (Zhong et al., 2021, «Sigmoid-Constrained Hypersphere Loss for Robust Face Recognition»), en MobileFaceNet-backbone, publisert i OpenCV Zoo under lisensen Apache 2.0. Den oppnår 99,40 % på LFW. Den tar inn et ansikt på 112 × 112 og returnerer 128 tall, en embedding; to fotoer av samme person gir embeddinger som peker samme vei.
Konverteringen gikk ONNX → PyTorch (onnx2torch) → Core ML (coremltools, ML Program, float16),
deretter lineær 8-bits kvantisering av vektene. Resultatet er på 9,8 MB, lastes på rundt 0,5 s første gang, og utdataene
stemmer med den opprinnelige ONNX-modellen med cosinus 0,998 på en testinput. Normaliseringen av input ligger inne i grafen, så
appen gir den vanlige RGB-piksler fra 0–255.
Justering betyr mer enn man skulle tro
SFace ble trent på ansikter justert etter en fast mal: øyne, nesetipp og munnviker på kjente steder i kvadratet på 112 × 112. Et ansikt som heller eller sitter skjevt, gir en merkbart dårligere embedding. Visions landemerker gir de fem punktene (pupillene, midten av neseområdet, de ytterste leppepunktene); Glimt finner så rotasjonen, den jevne skaleringen og forskyvningen som best flytter dem over på malen. I to dimensjoner har dette minste kvadraters-problemet en lukket løsning hvis man behandler punktene som komplekse tall:
a = Σ conj(zᵢ − z̄) · (wᵢ − w̄) / Σ |zᵢ − z̄|² // rotation + scale, one complex number
w = a · z + (w̄ − a · z̄) // the transform for any point z
Core Image utfører den (én affin transformasjon, programvarerenderer, 112 piksler ut), og utsnittet går videre til modellen. Referansefotoer får embedding to ganger, som de er og speilvendt, og de to snittes: en litt stødigere referanse helt gratis.
Er det samme barn? Kalibrering av terskelen
Appen sammenligner hvert ansikts embedding med referansefotoene ved hjelp av cosinuslikhet og beholder det beste treffet. Hvor grensen skulle gå, ble målt, ikke gjettet, på portretter fra Det hvite hus i public domain (offisielle portretter tatt med flere års mellomrom, og et familieportrett med begge foreldrene og to døtre):
Samme mann på portretter tatt med fire års mellomrom får 0,83; de samme personene plukket ut av familiefotoet 0,70–0,85. Fremmede holder seg under 0,25. Det vanskelige tilfellet er familie: to søstre i samme bilde får 0,43 mot hverandre, mor og døtre opptil 0,41 (samme lys og positur får slektninger til å ligne mer på hverandre), mens mor mot døtrene sine på et annet foto faller til 0,26–0,30. Derfor ligger grensen på 0,45: over søstrene, godt under samme person. Fem fotoer er en fornuftssjekk, ikke en evaluering, og grensen skal finjusteres på ekte familievideoer.
To regler til holder dobbeltgjengere ute: i en video holder ikke ett heldig bilde (det kreves to bilder på 0,45, eller ett klart over på 0,57), og når det er flere ansikter i et bilde, teller bare det som matcher best.
Flere referansefotoer
Ett referansefoto er én vinkel, ett lys og én alder. Barn forandrer seg fort. Glimt lar deg legge til opptil fem fotoer, og ansiktet i et bilde trenger bare å ligne på ett av dem, så et profilbilde eller ansiktet fra i fjor vinter fortsatt kan bli gjenkjent. Når et foto har flere personer, trykker du på riktig ansikt; Glimt gjetter aldri på «det største».
Å velge sekundet og beskjære det
Hvert bilde får en poengsum: 35 % hvor bra det ser ut, 20 % skarphet (variansen av en Laplace-operator på en grå kopi på 96 × 96: uskarpe bilder endrer seg sakte fra piksel til piksel), 45 % om det finnes et tydelig ansikt. Med referansefotoer teller hele den poengsummen 40 % og «er det barnet» 60 %: et helt vanlig bilde av barnet ditt slår et nydelig bilde av noen andre. Det valgte sekundet er vinduet med best gjennomsnitt, så ett godt bilde ved siden av et uskarpt vinner ikke.
Beskjæringen for en film i portrettformat hadde sin egen feil som er verdt å dele. Hvert bilde pekte ut det tydeligste ansiktet, og appen tok gjennomsnittet av posisjonene over sekundet. Med to barn vekslet det tydeligste ansiktet mellom dem, og gjennomsnittet havnet på veggen midt imellom. Nå peker hvert bilde ut barnet (eller det mest fremtredende ansiktet: størrelse × kvalitet, som er stødigere), og appen tar den største gruppen posisjoner som ligger tett sammen, ikke snittet. Når ansiktet er lite, zoomer utsnittet inn til det er omtrent en femtedel av bildehøyden, maks 1,6× for video.
Hvor raskt går det?
Overraskelsen: å kjenne igjen et ansikt er den billige delen, rundt 2 ms på Neural Engine. Å dekode videobildet koster femten ganger mer. I praksis kommer Glimt gjennom en travel dag med videoer på noen sekunder, og en måned på noen minutter.
Kjøring i bakgrunnen
Å fylle et år med manglende dager tar en stund, så det bør fortsette når du forlater appen. I iOS 26 er
BGContinuedProcessingTask laget for nettopp det: iOS viser fremdriften i Dynamic Island og på
låseskjermen. Tre ting vi lærte på den harde måten, alle fra en liten logg på enheten:
- Ingen GPU i bakgrunnen. Vision og Core ML velger GPU-en selv, feiler stille når appen ikke er i forgrunnen, og hvert bilde ser tomt ut. GPU-tilgang krever et spesielt entitlement og støttet maskinvare; iPhone 15 Pro rapporterte ingen.
- Men ikke alt kan falle tilbake på CPU-en. Å tvinge Vision over på CPU-en ødela ansiktsdeteksjonen: nettverket for ansiktskvalitet leveres uten CPU-vekter på iPhone («Missing weights path … nonane»). Glimt ber nå om Neural Engine først, så CPU-en, og faller ellers tilbake på enkle ansiktsbokser.
- Fremdriften må fortsette å bevege seg. En dag med en lang video fra iCloud sto stille i et halvt minutt, og iOS avsluttet oppgaven. Glimt melder nå fremdrift etter hvert analyserte bilde og hvert nedlastingssteg, og ber Photos om en versjon av hver video i middels kvalitet til analysen (filmene bruker fortsatt originalen).
Personvern
Glimt har ingen nettverkskode. Ansikter, embeddinger og valg blir værende i appens egen lagring på iPhone. Det eneste som kan røre nettverket, er Photos selv, når den henter dine egne videoer fra ditt eget iCloud Photos hvis de ikke ligger på telefonen.
Takk til: SFace av Yaoyao Zhong og kolleger; ONNX-konvertering av Chengrui Wang; OpenCV Zoo (Apache 2.0). Spørsmål eller ideer: glimt@theill.com.