2011-01-12 10 views
5

Sto tentando di applicare i filtri di fusione su due immagini (in questo caso HardLight). HardLight non è supportato nella libreria Android di base, quindi lo sto facendo manualmente su ciascun pixel. La prima esecuzione funziona, ma la velocità è inferiore a quella stellare. La generazione di un'immagine 500 x 500 da un'immagine di base 500 x 500 e un filtro 500 x 500 richiede troppo tempo. Questo frammento di codice viene utilizzato per generare anche le miniature (72x72) e integra il nucleo dell'applicazione. Mi piacerebbe qualche consiglio e/o suggerimenti su come accelerare questo.Ottimizzazione per fusione pixel su bitmap Android

Se si possono ottenere enormi guadagni ipotizzando che nessuna delle due immagini avrà alpha, va bene. NOTA: BlendMode e alpha sono valori non utilizzati nell'esempio (BlendMode sceglierà il tipo di blend, in questo caso HardLight hardcoded).

public Bitmap blendedBitmap(Bitmap source, Bitmap layer, BlendMode blendMode, float alpha) { 
    Bitmap base = source.copy(Config.ARGB_8888, true); 
    Bitmap blend = layer.copy(Config.ARGB_8888, false); 

    IntBuffer buffBase = IntBuffer.allocate(base.getWidth() * base.getHeight()); 
    base.copyPixelsToBuffer(buffBase); 
    buffBase.rewind(); 

    IntBuffer buffBlend = IntBuffer.allocate(blend.getWidth() * blend.getHeight()); 
    blend.copyPixelsToBuffer(buffBlend); 
    buffBlend.rewind(); 

    IntBuffer buffOut = IntBuffer.allocate(base.getWidth() * base.getHeight()); 
    buffOut.rewind(); 

    while (buffOut.position() < buffOut.limit()) { 
     int filterInt = buffBlend.get(); 
     int srcInt = buffBase.get(); 

     int redValueFilter = Color.red(filterInt); 
     int greenValueFilter = Color.green(filterInt); 
     int blueValueFilter = Color.blue(filterInt); 

     int redValueSrc = Color.red(srcInt); 
     int greenValueSrc = Color.green(srcInt); 
     int blueValueSrc = Color.blue(srcInt); 

     int redValueFinal = hardlight(redValueFilter, redValueSrc); 
     int greenValueFinal = hardlight(greenValueFilter, greenValueSrc); 
     int blueValueFinal = hardlight(blueValueFilter, blueValueSrc); 

     int pixel = Color.argb(255, redValueFinal, greenValueFinal, blueValueFinal); 

     buffOut.put(pixel); 
    } 

    buffOut.rewind(); 

    base.copyPixelsFromBuffer(buffOut); 
    blend.recycle(); 

    return base; 
} 

private int hardlight(int in1, int in2) { 
    float image = (float)in2; 
    float mask = (float)in1; 
    return ((int)((image < 128) ? (2 * mask * image/255):(255 - 2 * (255 - mask) * (255 - image)/255))); 

} 
+0

Ciao, puoi aiutarmi su come usare alpha in questa funzione? –

risposta

0

C'era una domanda come questa un po 'indietro (Link). Non sono sicuro che l'OP abbia mai risolto il suo problema.

Quello che ho fatto nel mio caso per ottenere una "miscela di photoshop" è stato applicare una sovrapposizione di ombre tranlucenti a un singolo colore. Era semplicemente una questione del mio grafico che stava cercando di capire come sovrapporre l'ombra. Ha funzionato alla grande e ho completamente ignorato il problema di dover scorrere i pixel in una bitmap (stavo usando getPixels() e setPixels()). La parte difficile è stata davvero alla fine dei miei designer, ma una volta che l'ha capito, ha generato una serie di immagini dall'aspetto fantastico.

Ho utilizzato fondamentalmente una maschera alfa (per generare colori dinamici) con la sovrapposizione delle ombre. Mi piacerebbe conoscere una soluzione tramite codice, quindi buona fortuna a te!

Modifica: Inoltre, non ho familiarità con BlendMode. Non l'hai mai usato nel tuo metodo. Cos'è questa, una lezione personalizzata?

+0

Sfortunatamente, questa soluzione non funzionerà nel mio caso. – MarkPowell

2

Le operazioni in virgola mobile sono generalmente più lente del numero intero, anche se non posso dire nulla su Android in particolare. Mi chiedo perché stai convertendo l'input in hardlight in virgola mobile, quando le operazioni sembrano funzionare perfettamente come numeri interi?

È anche possibile ottenere una velocità inserendo la formula in linea nel ciclo anziché richiamare una funzione. O forse no, ma vale la pena provare e fare benchmark.

+0

Provando cose diverse, sono stato in grado di ottenere un incremento delle prestazioni del 40% utilizzando i vettori int invece dei Buffer (usando 'getPixels()' e 'setPixels()'), e non convertendo i valori in float in 'hardlight' . A parte questo, penso che le migliori prestazioni che otterrai siano quelle di portare il calcolo a livello nativo, magari implementando un Xfermode personalizzato. –

+0

hmm, passando a getPixels()/setPixels() ho visto un doppio nel tempo di calcolo, a meno che non abbia frainteso quello che stai dicendo? – MarkPowell

+0

@MarkPowell, penso che @Kevin stesse discutendo a favore di array int e discutendo * contro * getPixels/setPixels. Dovrai indirizzare il tuo commento su di lui avviandolo con @Kevin se hai altre domande. –

1

Anche se si può sacrificare 3 bit/pixel di qualità finale dell'immagine/precisione, - siamo in grado di vincere circa il 25% di guadagno delle prestazioni in funzione hardlight(), riscrivendo con gli operatori bit-saggio:

int hardlight(int image, int mask) { 
    return (((image < 128) ? 
      ((((mask << 1) * image) >> 8)): 
      (255^((((255^mask) << 1) * (255^image)) >> 8)))); 
} 
+0

Grazie, vedendo un miglioramento della velocità generale del 10% con questo. Tuttavia, andando a vedere se il sacrificio di 3 bit/pixel è fattibile. – MarkPowell

+0

Ok. È un peccato che il guadagno di prestazioni sia solo del 10% anziché del 25% come nel mio computer Windows.Sospetto che gli operatori bit a bit di Android siano meno ottimizzati rispetto al compilatore Windows VS/MS VS C/C++. O forse il collo di bottiglia principale delle prestazioni non è nella funzione hardlight ma da qualche altra parte. –