2009-09-25 7 views
5

Il mio ciclo interno contiene un calcolo che la profilazione mostra essere problematica.Formula veloce per una curva di "contrasto elevato"

L'idea è di utilizzare un pixel in scala di grigi x (0 < = x < = 1) e "aumentare il contrasto". Miei requisiti sono abbastanza sciolto, solo il seguente:

  • per x < 0,5, 0 < = f (x) x <
  • per x> 0,5, x < f (x) = 1 <
  • f (0) = 0
  • f (x) = 1 - f (1 - x), ossia deve essere "simmetrico"
  • Preferibilmente, la funzione deve essere liscia.

Così il grafico deve essere simile a questa:

Graph.

ho due implementazioni (i risultati sono diversi, ma entrambi sono conforme):

float cosContrastize(float i) { 
    return .5 - cos(x * pi)/2; 
} 

float mulContrastize(float i) { 
    if (i < .5) return i * i * 2; 
    i = 1 - i; 
    return 1 - i * i * 2; 
} 

Quindi chiedo sia un microoptimization per una di queste implementazioni, o un originale, più veloce formula di tua scelta.

Forse uno di voi può anche girarsi i bit;)

+0

Forse potremmo aiutarti meglio se puoi dirci quale lingua stai usando (presumo Java) e cosa implica il compilatore/runtime. –

+0

C# con un compilatore MS e runtime, ma sono disposto a riscrivere l'algoritmo critico in C++ se trovo che devo ... –

+0

C# con i nomi dei metodi camelCased? :( – Joren

risposta

5

Banalmente si potrebbe semplicemente soglia, ma immagino che questo è troppo stupido:

return i < 0.5 ? 0.0 : 1.0; 

Dal momento che si parla di 'aumentando il contrasto' Suppongo che il i valori di input sono valori di luminanza. Se è così, e sono discreti (forse è un valore di 8 bit), potresti usare una tabella di ricerca per farlo abbastanza velocemente.

Il tuo 'mulContrastize' sembra abbastanza veloce. Un'ottimizzazione sarebbe utilizzare la matematica intera. Diciamo, ancora una volta, che i valori di input potrebbero essere effettivamente passati come un valore senza segno a 8 bit in [0..255]. (? Anche in questo caso, forse un bel presupposto) Si potrebbe fare qualcosa o meno così ...

int mulContrastize(int i) { 
    if (i < 128) return (i * i) >> 7; 
    // The shift is really: * 2/256 
    i = 255 - i; 
    return 255 - ((i * i) >> 7); 
+0

Una soglia è troppo lenta per essere utile nel mio caso. Sono valori di luminanza, sì. Non sono valori discreti - sono in realtà float, per due motivi. OpenGL, le trame mobili sono le più veloci e in secondo luogo, ho preso la decisione di usare i float 0.0-1.0 per rendere i miei calcoli facili * e * veloci, ma non ho mai pensato di contrastare con una tabella di ricerca, cercherò supera l'interesse per la trama di OpenGL: l'implementazione che hai postato è bella, ma non bella come una tabella di ricerca e il mio mulContrastize è "abbastanza veloce", ma non in un ciclo così ristretto :) –

+0

Btw, non dovresti t dividere per 255 due volte, solo una volta. Quindi dovresti passare da 7. –

+0

Oops hai ragione, che normalizza un passo troppo lontano. Risolverà l'esempio –

13

Considerare i seguenti sigmoide funzioni sagomate (correttamente tradotte alla gamma desiderata):

screenshot


I generato figura sopra utilizzando MATLAB. Se interessato, ecco il codice:

x = -3:.01:3; 
plot( x, 2*(x>=0)-1, ... 
     x, erf(x), ... 
     x, tanh(x), ... 
     x, 2*normcdf(x)-1, ... 
     x, 2*(1 ./ (1 + exp(-x)))-1, ... 
     x, 2*((x-min(x))./range(x))-1 ) 
legend({'hard' 'erf' 'tanh' 'normcdf' 'logit' 'linear'}) 
+1

+1. molto bene. –

+1

Il problema principale dell'OP è la velocità. Come accelerano queste cose? – tom10

+0

Grazie, almeno so che ora sono chiamati 'sigmoid';) Ho fatto un'implementazione semplice con tanh, è veloce come quella del cos. Il resto richiederà un bel po 'di riflessione e penso che saranno più lenti ma vedremo. –

4

Un'interpolazione a tratti può essere rapida e flessibile.Richiede solo alcune decisioni seguite da una moltiplicazione e un'aggiunta e può approssimare qualsiasi curva. Evita anche la routine che può essere introdotta dalle tabelle di ricerca (o il costo aggiuntivo in due ricerche seguite da un'interpolazione per appianare questo), sebbene il lut possa funzionare perfettamente per il tuo caso.

alt text http://i35.tinypic.com/fbeu0j.png

Con pochi segmenti, è possibile ottenere una buona partita. Qui ci sarà courseness nel colore gradienti, che sarà molto più difficile da rilevare rispetto alla courseness nei colori assoluti.

Come sottolinea Eamon Nerbonne nei commenti, la segmentazione può essere ottimizzata "scegliendo [i] punti di segmentazione in base a qualcosa come la derivata seconda per massimizzare i dettagli", ovvero dove la pendenza cambia maggiormente. Chiaramente, nel mio esempio pubblicato, avere tre segmenti nel mezzo del caso dei cinque segmenti non aggiunge molti più dettagli.

+2

E se sei davvero eccentrico, puoi scegliere i tuoi punti di segmentazione in base a qualcosa come la derivata seconda per massimizzare i dettagli (nessun punto nel differenziare i segmenti nel segmento centrale, abbastanza dritto). –

+0

@Eamon: Grazie per la seconda idea derivativa. Sapevo di essere pigro con i punti centrali, ma mi piace molto la generalizzazione della seconda derivata. – tom10

Problemi correlati