2015-12-27 13 views
6

Sto provando a creare uno sfondo e sto utilizzando la conversione HSV nella classe "android.graphics.color". Sono rimasto molto sorpreso quando ho realizzato che la conversione di un colore HSV creato con una tonalità specificata (0..360) in un colore rgb (un intero) e una conversione posteriore in un colore HSV non produrrebbe la stessa tonalità. Questo è il mio codice:Conversione HSV imprecisa su Android

int c = Color.HSVToColor(new float[] { 100f, 1, 1 }); 
float[] f = new float[3]; 
Color.colorToHSV(c, f); 
alert(f[0]); 

Sto iniziando con una tonalità di 100 gradi e il risultato è 99.76471. Mi chiedo perché c'è (secondo me) inesattezza relativamente grande.

Ma un problema molto più grande è che quando si inserisce nuovamente questo valore nel codice, il nuovo risultato diminuisce di nuovo.

int c = Color.HSVToColor(new float[] { 99.76471f, 1, 1 }); 
float[] f = new float[3]; 
Color.colorToHSV(c, f); 
alert(f[0]); 

Se inizio con 99.76471, ottengo 99.52941. Questo è un po 'un problema per me. Ho fatto qualcosa di simile in java con la classe "java.awt.Color" in cui non avevo questi problemi. Sfortunatamente, non posso usare questa classe in Android.

+0

I * credo * questo è un caso di conversione diversa utilizzata tra un numero intero a 16 e 32 bit, tuttavia questo potrebbe essere diverso. Ricordo alcuni anni fa che si è verificato un problema con i file audio e la conversione da un array di byte. Alla fine ho solo arrotondato la figura fino al più vicino int intero. – dave

+1

Sostengo l'idea di dave. Una cosa che potrebbe essere utile è notare che la differenza tra il valore originale di 100 e il risultato arrotondato di 99.76471 è 60/255 e 255 = 2^8-1 (È abbastanza comune memorizzare valori rgb su 8 bit) . Lo stesso vale per 99.76471 e 99.52941. Non ho una teoria completa, ma sembra che l'aritmetica di base sia andata storta. – elias

risposta

1

Questo è un problema interessante. Non è evitabile con la classe Android a causa della bassa precisione di galleggiamento. Tuttavia, ho trovato una soluzione simile scritta in javascript here.

Se è abbastanza importante per voi desidera definire un proprio metodo/classe per fare le conversioni, qui è una conversione Java che dovrebbe dare una migliore precisione:

@Size(3) 
/** Does the same as {@link android.graphics.Color#colorToHSV(int, float[])} */ 
public double[] colorToHSV(@ColorInt int color) { 
    //this line copied vertabim 
    return rgbToHsv((color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF); 
} 

@Size(3) 
public double[] rgbToHsv(double r, double g, double b) { 
    final double max = Math.max(r, Math.max(g, b)); 
    final double min = Math.min(r, Math.min(g, b)); 
    final double diff = max - min; 
    final double h; 
    final double s = ((max == 0d)? 0d : diff/max); 
    final double v = max/255d; 
    if (min == max) { 
     h = 0d; 
    } else if (r == max) { 
     double tempH = (g - b) + diff * (g < b ? 6: 0); 
     tempH /= 6 * diff; 
     h = tempH; 
    } else if (g == max) { 
     double tempH = (b - r) + diff * 2; 
     tempH /= 6 * diff; 
     h = tempH; 
    } else { 
     double tempH = (r - g) + diff * 4; 
     tempH /= 6 * diff; 
     h = tempH; 
    } 
    return new double[] { h, s, v }; 
} 

devo confessare l'ignoranza qui - Ho fatto una rapida conversione e non ho avuto il tempo di testare correttamente. Potrebbe esserci una soluzione più ottimale, ma questo dovrebbe iniziare almeno.

+0

Beh, sembra che il doppio più preciso non risolva il mio problema perché sta ancora arrotondando a un int e potrebbe esserci il problema che non ottengo lo stesso valore indietro – user2957782