Best practice per l'elaborazione parallela delle immagini

2

Quando si esegue (possibilmente pesante) l'elaborazione dei pixel su un'immagine grande, il multithreading diventa obbligatorio. Lo studio standard prevede l'avvio di un ciclo i cui indici sono partizionati in più thread all'interno di un pool di thread. I vantaggi prestazionali diventano immediatamente evidenti dopo aver preso le misure di sicurezza del filo appropriate per garantire la correttezza dei risultati.

Tuttavia, ci sono diverse configurazioni possibili su come si possano partizionare gli indici. I metodi più comuni sono il partizionamento per riga o per pixel. Ecco la mia interpretazione dei vantaggi e degli svantaggi di ciascuno:

Per riga:

  • Meno spese generali di creazione dei thread

  • Il caricamento del thread potrebbe non essere nemmeno dovuto al numero di righe che potrebbero non essere divisibili per il numero di thread. Ciò può causare un'immagine ampia ma non alta da elaborare in modo inefficiente su più core

Per pixel:

  • Altro overhead per la creazione di thread

  • Il carico di thread può essere distribuito in modo più uniforme a causa del fatto che il tempo necessario per elaborare gli indici che non sono divisibili per il numero di thread è relativamente piccolo

La mia interpretazione è corretta, o c'è di più nella storia? Dovrei sempre scegliere uno rispetto all'altro?

Per riferimento, sto usando la funzione Parallel.For () in C #.

    
posta MathuSum Mut 08.11.2016 - 20:03
fonte

2 risposte

1

Uso un approccio in cui ogni compito ottiene ltrb rect insieme ai pixel per rappresentare una regione rettangolare dell'immagine da elaborare.

Questo mi consente di prendere quei casi in cui un'immagine è molto più larga di quanto sia alta e ancora divisa in blocchi rettangolari da elaborare con, diciamo, 1024 pixel da elaborare per thread. Per le immagini di piccole dimensioni con meno di 1024 pixel in totale, non mi preoccupo nemmeno di applicare un ciclo di loop parallelo poiché ho trovato che è generalmente più economico utilizzare solo un ciclo a thread singolo in questi casi.

Normalmente non otterrai prestazioni così buone cercando di assegnare un pixel per attività. Almeno con librerie come OMP e TBB, è necessaria una quantità sufficiente di lavoro da svolgere in ogni attività, altrimenti il sovraccarico di pianificazione delle attività supererà i vantaggi del multithreading al punto in cui si può facilmente peggiorare rispetto alle prestazioni a thread singolo.

Inoltre, a meno che i tuoi algoritmi di immagine non si preoccupino delle posizioni dei pixel che stanno processando, questo porta un altro sovraccarico di dover passare la coordinata di pixel per pixel.

Quindi ti consiglio di processare in blocchi rettangolari come faccio io o anche di avere ogni thread che processa una scanline non è male e sarà generalmente abbastanza buono per i casi più comuni.

    
risposta data 17.12.2017 - 05:53
fonte
1

Dovresti considerare di spostare questo lavoro sulla GPU. È stato progettato per l'elaborazione in parallelo e molte attività di elaborazione delle immagini rientrano in questa categoria. Spesso ha anche migliaia di core invece di poche decine di CPU moderne. Il sovraccarico di caricamento sulla scheda e il download in memoria è spesso sminuito dalla velocità di elaborazione, a meno che l'elaborazione non sia estremamente semplice. I nuclei GPU opereranno spesso su un frammento alla volta, che di solito è simile a un'area di 2x2 pixel. Nella mia esperienza è facile sostenere 30 fps per video HD (1920 x 1080) e colpire 60 non è troppo difficile. È anche possibile eseguire l'elaborazione in tempo reale di filmati 4K, in molti casi.

Per un esempio di un uso estremamente efficiente della GPU per l'elaborazione delle immagini, consiglio di guardare il CoreImage di Apple e in particolare la classe CIFilter. Anche se non stai lavorando su macOS, le idee possono essere applicate su altri sistemi. Esistono piccoli kernel espressi come frammenti di shader. Consentono la concatenazione di questi shader per ridurre il numero di buffer intermedi coinvolti.

    
risposta data 17.12.2017 - 06:57
fonte