2015-12-27 8 views
6

Ich versuche ein Hintergrundbild zu erstellen und verwende die HSV-Konvertierung in der Klasse "android.graphics.color". Ich war sehr überrascht, als mir klar wurde, dass eine Konvertierung einer erstellten HSV-Farbe mit einem bestimmten Farbton (0..360) in eine RGB-Farbe (eine Ganzzahl) und eine Rückkonvertierung in eine HSV-Farbe nicht den gleichen Farbton ergibt. Das ist mein Code:Ungenaue HSV-Konvertierung unter Android

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

Ich beginne mit einem Farbton von 100 Grad und das Ergebnis ist 99.76471. Ich frage mich, warum es (meiner Meinung nach) eine relativ große Ungenauigkeit gibt.

Aber ein viel größeres Problem ist, dass wenn Sie diesen Wert erneut in den Code eingeben, das neue Ergebnis wieder abnimmt.

Wenn ich mit 99.76471 beginne, bekomme ich 99.52941. Das ist ein Problem für mich. Ich habe etwas ähnliches in Java mit der "java.awt.Color" -Klasse, wo ich diese Probleme nicht hatte. Leider kann ich diese Klasse nicht in Android verwenden.

+0

Ich * glaube * Dies ist ein Fall einer anderen Konvertierung zwischen einer 16 und 32-Bit-Ganzzahl verwendet, aber das kann weg sein. Ich erinnere mich, dass ich vor Jahren ein Problem mit Sounddateien und der Konvertierung von einem Byte-Array hatte. Am Ende rundete ich die Figur auf das nächste ganze int. – dave

+1

Ich unterstütze die Idee von dave. Eine Sache, die nützlich sein könnte, ist zu bemerken, dass der Unterschied zwischen dem ursprünglichen Wert von 100 und dem gerundeten Ergebnis von 99.76471 60/255 ist, und 255 = 2^8-1 (Es ist ziemlich üblich, rgb-Werte auf 8 Bits zu speichern) . Das gleiche gilt für 99.76471 und 99.52941. Ich habe keine vollständige Theorie, aber es scheint, als wäre die grundlegende Arithmetik falsch gelaufen. – elias

Antwort

1

Dies ist ein interessantes Problem. Es ist nicht vermeidbar mit der Android-Klasse wegen der niedrigen Float-Präzision. Allerdings habe ich eine ähnliche Lösung in Javascript here geschrieben.

Wenn es wichtig ist genug für Sie Ihre eigene Methode/Klasse definieren möchten die Konvertierungen zu tun, hier ist eine Java-Konvertierung, die Sie bessere Präzision geben sollte:

@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 }; 
} 

Ich habe hier Unwissenheit zu bekennen - Ich habe eine schnelle Konvertierung durchgeführt und keine Zeit gehabt, um richtig zu testen. Es könnte eine bessere Lösung geben, aber das sollte Ihnen zumindest helfen.

+0

Nun, es scheint, dass das präzisere double mein Problem nicht löst, weil es immer noch auf ein int aufrundet und es könnte das Problem geben, dass ich nicht den gleichen Wert zurückbekomme – user2957782

Verwandte Themen