2013-10-04 4 views
8

Ho un'immagine di binaria, il binario valore di è 0 o 255. il tipo di dati di immagine è unsigned char. Qui ho bisogno di fare un filtraggio mediano su questa immagine.Eliminare ramificazione quando ritrovamento mediano in un binario {0, 255} immagine

Penso che usando un istogramma per trovare la mediana dovrebbe essere veloce. Utilizzando alcuni codici per spiegare:

unsigned int hist[2] = {0, 0}; 

for (int i = 0; i < kernel_h; ++i) { 
    for (int j = 0; j < kernel_w; ++j) { 
      if (image(i,j) == 0) { 
       hist[0]++; 
      } 
      else { 
       hist[1]++; 
      } 
    } 
} 

Quindi, è possibile ottenere il valore medio molto velocemente. Ma a causa di questo caso, i codici ancora potrebbe essere migliorato:

int counter = 0; 

for (int i = 0; i < kernel_h; ++i) { 
    for (int j = 0; j < kernel_w; ++j) { 
      if (image(i,j) == 0) { 
       counter++ 
      } 
      else { 
       counter--; 
      } 
    } 
} 

Ma mi chiedo c'è qualche altro modo per eliminare il ramo if-else, come l'utilizzo di operazioni su bit per mappare {0, 255} a qualcosa di così che potremmo semplicemente aggiornare una bandiera senza diramazioni.

Qualcuno suggerimento?

+0

La vettorizzazione è un'opzione per te? E su quale piattaforma sei? I filtri mediani 3x3 e 5x5 su immagini binarie sono banalmente vettorizzabili su entrambi i processori x86 e ARM, utilizzando estensioni SSE, NEON o DSP. Su dati in formato byte, dovresti essere in grado di elaborare 16 pixel contemporaneamente con SSE. –

risposta

10

Tutti i bit di 255 sono 1 in modo da poter semplificare che "se" per:

hist[image(i,j) & 1]++; 

Se si desidera utilizzare il contatore si può fare:

counter += (image(i,j) & 2)-1; 
+0

Wow! Grazie mille! – blackball

+1

L'esempio 'counter' può essere ulteriormente semplificato. Stai facendo le sottrazioni 'kernel_h * kernel_w' di -1 ciascuna, che sono facilmente sollevate dal ciclo in un singolo' counter - = kernel_w * kernel_h'. – MSalters

+0

@EricPostpischil: Il '& 2' ti dà +2 o 0. Il codice originale usato counter ++ e counter--, quindi +1 e -1. La differenza per pixel è una costante -1. – MSalters

5

Questo calcolo può essere fatto MOLTO più veloce e più specificamente O(n) nel numero di pixel e indipendente dalle dimensioni del kernel.

L'idea è di eseguire prima una "conversione di scansione" calcolando uno summed area table in cui il valore di ciascun pixel (x, y) viene sostituito dalla somma di tutti i pixel da (0, 0) a (x, y) .

Dato questo è possibile sapere in tempo fisso il numero di pixel si trovano in qualsiasi rect utilizzando

st(x0, y0) + st(x1, y1) - st(x0, y1) - st(x1, y0) 

e dato che ogni pixel è 0 o 1 la somma che dà il conteggio di quelli.

Il tempo di calcolo totale è O(n) per creare la tabella delle somme e O(n) per eseguire il filtraggio mediano, indipendentemente dalla dimensione dell'area in cui eseguire il conteggio.

Nel caso della mediana filtraggio si potrebbe precompute il risultato a seconda della somma e la formula nel ciclo interno potrebbe essere:

result[x] = res[p0[x] + p1[x+box] - p0[x+box] - p1[x]]; 

Inoltre tabella somma non ha bisogno di essere calcolato completamente (così richiede un numero intero per pixel) ma potrebbe essere calcolato "pigramente" mentre si esegue il risultato ed è necessario solo il numero di righe della tabella rispetto all'altezza del kernel mantenendo il tempo di calcolo O(image_width*image_height) ma richiede solo la memoria kernel_height*image_width.

+0

Sì, hai ragione, l'uso di un'immagine integrale (o sum-table) potrebbe essere un modo migliore se l'immagine o il kernel è relativamente più grande. Ma per implementare questo algoritmo, abbiamo bisogno di un altro blocco del buffer di memoria, e per ogni finestra del kernel, dobbiamo fare una divisione per ottenere il numero di * 1 *. Qui la mia dimensione del kernel è piccola, ad es. 3x3 o 5x5, e anche la dimensione dell'immagine è piccola. Quindi scelgo il modo semplice per fare il mio lavoro. – blackball

+0

@ user1786323: vedere modifica. La divisione può essere banalmente evitata usando una tabella di ricerca con elementi 'kernel_area'. – 6502

Problemi correlati