Pipeline volti

Multi-pass Vision, blur ellittico, pennello manuale e ripristino dall'originale.

Flusso automatico

  1. Orientamento — EXIF → CIImage.oriented(forExifOrientation:), così Vision e il salvataggio lavorano su pixel upright.
  2. Downscale solo per detection — lato lungo max 1920px; la sfocatura resta a piena risoluzione.
  3. Multi-pass Vision — sull’immagine (e su varianti preprocessate) partono:
    • VNDetectFaceLandmarksRequest
    • VNDetectFaceRectanglesRequest
  4. Deduplica — IoU > 0.45 → stesso volto; preferenza a osservazioni con landmarks e confidence più alta.
  5. Regione blur — bounding box ristretto al volto (≈90% altezza + padding); se ci sono landmarks, il box segue contour e sopracciglia evitando strisce sui capelli.
  6. BlurCIGaussianBlur + maschera CIRadialGradient ellittica blended con CIBlendWithMask.

Preprocess per il recall

Oltre all’originale, ogni pass genera una variante e la scarta subito (autoreleasepool):

FiltroParametriPerché
CIExposureAdjustEV +0.8 / +1.5volti in ombra
CIColorControlsbrightness +0.18, contrast 1.35scene piatte
CIGammaAdjustpower 0.65controluce

Intensità

Lo slider UI mappa 0.25…0.85 (etichette Leggera / Media / Forte). Il raggio blur è:

radius = max(8, min(w, h) * (0.04 + intensity * 0.07))

cambiando solo l’intensità, Vision non viene rieseguito: si riapplicano le faceRegions cacheate sull’originale.

Pennello manuale

BlurSpot è normalizzato (centro 0–1, raggio rispetto al lato corto). In modalità Sfocatura manuale ogni tap aggiunge uno spot e lo applica a caldo. In modalità Ripristina censura lo stesso formato di spot guida un blend dall’immagine originale verso quella corrente — stessa maschera ellittica, sorgente diversa.

Gli spot manuali sopravvivono a un cambio di intensità: dopo il re-blur automatico vengono riapplicati in ordine.

Filigrana e salvataggio

WatermarkService disegna il logo Talea (~18% del lato corto, opacità 0.45) in basso a destra solo su displayImage. Il salvataggio:

  • riusa l’UTI originale (JPEG/PNG/…);
  • forza orientation = 1 dopo aver raddrizzato i pixel;
  • per JPEG usa qualità lossy = 1.0;
  • scrive con PhotoKit addOnly.

Memoria

Vincoli pratici adottati:

  • cacheIntermediates: false sul CIContext;
  • una variante Vision per volta dentro autoreleasepool;
  • history limitata a 10 frame;
  • cache watermark invalidata quando cambia la source image.