Basi dell’elaborazione immagini con web worker
I web worker eseguono lavoro pesante fuori dal thread dell’interfaccia. Nell’elaborazione immagini questo significa che il ritaglio può procedere mentre la UI resta reattiva, entro i limiti di memoria e CPU del dispositivo.
Non cambia dove vanno i pixel: cambia come il browser organizza il lavoro in locale.
Il thread principale ha un lavoro di interfaccia utente
Una pagina del browser normalmente esegue JavaScript su un thread principale. Questo thread coordina anche il layout, la pittura e l’input. Se lo occupa un lungo calcolo, i clic potrebbero risultare ritardati, l’animazione potrebbe interrompersi e il browser potrebbe avvisare che la pagina non risponde.
Un editor di immagini ha molte responsabilità sul thread principale prima ancora che inizi l’inferenza:
- ricevere una selezione di file, incollarla o rilasciarla;
- decodificare e visualizzare un’immagine;
- aggiornare gli stati di avanzamento e di errore;
- disegnare la tela di anteprima;
- gestire il movimento del pennello Aggiungi e Cancella;
- preparare azioni di download o appunti.
Mettere il lavoro numerico di un modello di segmentazione sullo stesso thread farebbe sì che tali compiti competano direttamente. Un lavoratore crea un confine più chiaro.
Il confine basato sul messaggio
L’editor e il lavoratore non condividono variabili ordinarie. Comunicano inviando messaggi. Un flusso semplificato è simile al seguente:
- L’editor crea o riutilizza un lavoratore.
- Chiede al lavoratore di inizializzare il runtime e il modello di inferenza.
- Prepara i dati dell’immagine e invia una richiesta di inferenza.
- Il lavoratore converte i dati nell’input previsto del modello.
- Il lavoratore esegue il modello e produce i valori della maschera.
- Restituisce la maschera o i dati dei risultati.
- L’editor compone l’anteprima e consente il perfezionamento o l’esportazione.
I messaggi dovrebbero includere un contesto sufficiente per abbinare una risposta alla richiesta corretta. Ciò è importante se un utente sceglie un’altra immagine prima che finisca il lavoro precedente. L’interfaccia deve evitare di visualizzare un vecchio risultato su una nuova fonte.
Copia e trasferimento dei dati dell’immagine
Inviare un piccolo SMS è economico. L’invio di milioni di valori di pixel può essere costoso se il browser deve copiare l’intero buffer. Le API Web possono invece trasferire la proprietà di determinati buffer binari. Un buffer trasferito diventa disponibile per il destinatario senza conservare un duplicato utilizzabile dal lato mittente.
Questa ottimizzazione comporta un vincolo di progettazione: dopo il trasferimento, il mittente non può continuare a utilizzare lo stesso buffer come se fosse ancora proprietario dei dati. Un editor può mantenere una rappresentazione di visualizzazione separata, creare un buffer di inferenza dedicato o ricostruire ciò di cui ha bisogno in seguito.
Non tutte le implementazioni utilizzano il trasferimento esattamente negli stessi posti. La lezione generale è che la separazione dei thread non fa scomparire lo spostamento dei dati. Le dimensioni dell’immagine, la dimensione del buffer e il numero di conversioni influiscono ancora sulla latenza e sulla memoria.
Cosa mette Easy Background Remover nel lavoratore
Easy Background Remover utilizza un Web Worker con un runtime di inferenza del browser per la segmentazione sul dispositivo. La pesante fase di ritaglio automatico produce una maschera. L’editor visualizza quindi il risultato composito e supporta il perfezionamento del pennello CPU-canvas.
Questa separazione fornisce ai fallimenti un confine più utile. Se il lavoratore non riesce a inizializzarsi o si blocca durante l’inferenza, l’interfaccia può segnalare un errore relativo al lavoratore invece di fare affidamento su una scheda permanentemente bloccata come unico segnale.
Inoltre, mantiene comprensibile la richiesta di elaborazione locale. L’invio di pixel da una pagina di estensione al proprio lavoratore è una comunicazione all’interno dell’ambiente del browser, non un caricamento su un’API di ritaglio remota. La prima sessione può scaricare separatamente l’asset modello riutilizzabile; vedere Perché la prima esecuzione scarica un modello.
Un lavoratore non effettua il calcolo istantaneo
I lavoratori migliorano la reattività, non la capacità grezza del dispositivo. Il modello consuma comunque CPU, GPU o altre risorse di runtime in base a ciò che il browser può fornire. Un input di grandi dimensioni può comunque richiedere più tempo e più memoria di uno piccolo.
Rimangono diversi limiti:
- l’inizializzazione del modello ha un costo reale;
- i buffer dei pixel occupano memoria su entrambi i lati se copiati;
- il ridimensionamento e la conversione del formato richiedono tempo;
- i dispositivi con poca memoria potrebbero avere difficoltà con immagini di grandi dimensioni;
- più lavoratori possono aumentare la contesa invece di ridurla;
- Gli aggiornamenti di esportazione e tela possono comunque coinvolgere il thread principale.
Avviare cinque inferenceworker per cinque immagini non è automaticamente cinque volte più veloce. Gli operai condividono la stessa macchina. I lavori paralleli possono competere per la larghezza di banda della memoria e le risorse di esecuzione, mentre ciascuna istanza del modello può comportare il proprio costo di memoria.
Il reporting sui progressi è cooperativo
Un lavoratore può inviare messaggi di stato, ma non sa automaticamente quale percentuale di avanzamento riterrà accurata. Il download del modello, l’inizializzazione del runtime, la preparazione dell’input, l’inferenza, la conversione della maschera e il rendering dell’anteprima sono fasi separate con tempistiche diverse.
Alcune fasi hanno conteggi di byte misurabili. L’esecuzione di un singolo modello può esporre solo “iniziato” e “finito”. Una percentuale uniforme che avanza in modo uniforme può quindi essere estetica piuttosto che una misurazione precisa.
L’utile interfaccia utente di avanzamento nomina la fase quando possibile: preparazione del modello, elaborazione dell’immagine o risultato della costruzione. Gestisce anche il fallimento e la cancellazione invece di lasciare uno spinner senza spiegazione.
La cancellazione è più che nascondere uno spinner
Se l’utente chiude un’immagine o ricomincia, l’interfaccia può ignorare l’eventuale risposta dalla richiesta obsoleta. L’interruzione immediata del calcolo sottostante potrebbe richiedere ulteriore supporto da parte del runtime o la terminazione e la ricreazione del lavoratore.
Terminare un lavoratore è decisivo, ma ne scarta lo stato inizializzato. Il lavoro successivo potrebbe dover caricare e inizializzare nuovamente il modello. Per un’operazione breve, contrassegnare il risultato come obsoleto può essere più economico che abbattere tutto.
La scelta corretta dipende dal carico di memoria, dalla durata dell’operazione e dalle capacità di runtime. Dal punto di vista dell’utente, la regola importante è che il lavoro obsoleto non deve sovrascrivere la modifica corrente.
Anche gli errori devono oltrepassare il limite
Un’eccezione all’interno di un lavoratore non diventa una normale eccezione del thread principale. Il lavoratore deve segnalare errori utilizzabili e l’editor deve ascoltare gli errori a livello di lavoratore.
Una buona gestione degli errori distingue almeno:
- risorsa modello non disponibile;
- inizializzazione del modello fallita;
- la decodifica dell’immagine o la preparazione dell’input non sono riuscite;
- inferenza fallita;
- il lavoratore si è fermato improvvisamente;
- il risultato non appartiene più alla richiesta corrente.
Questo è più attuabile di un generico “qualcosa è andato storto”, soprattutto quando la configurazione di prima esecuzione e la normale elaborazione delle immagini hanno rimedi diversi.
L’output dei lavoratori è ancora solo una prima maschera
L’architettura del thread non migliora di per sé un bordo ambiguo. L’operatore può restituire una maschera tecnicamente valida a cui mancano ancora pelliccia, materiale trasparente, spalline strette o un’ombra desiderata. Queste sono domande sulla segmentazione e sull’intento.
Il lavoro dell’editor riprende dopo l’inferenza: ridimensiona la maschera nel sistema di coordinate di lavoro, componi un’anteprima, lascia che l’utente la rifinisca ed esporta lo stato corrente. Risoluzione della maschera e dimensione dell’anteprima spiega perché questi sistemi di coordinate non devono essere confusi.
Un modello mentale conciso
Pensa al lavoratore come a uno specialista locale dietro una finestra di messaggio:
- l’editor è proprietario dell’interazione;
- spetta al lavoratore il compito di inferenza pesante;
- i dati dell’immagine binaria attraversano un confine definito;
- il lavoratore restituisce una maschera, non un giudizio finito su ogni bordo;
- L’editore rimane responsabile dello stato attuale, della revisione, del perfezionamento e dell’esportazione.
Per la visualizzazione dei pixel stessi da parte del modello, continuare con Cosa vede un modello di ritaglio sul dispositivo. Per una panoramica pratica end-to-end, vedere Come funziona la rimozione dello sfondo locale.