2015-12-27 5 views
6

Я пытаюсь создать обои, и я использую преобразование HSV в классе «android.graphics.color». Я был очень удивлен, когда понял, что преобразование созданного цвета HSV с заданным оттенком (0..360) в цвет rgb (целое число) и обратное преобразование в цвет HSV не приведет к тому же оттенку. Это мой код:Неверное преобразование HSV на Android

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

Я начинаю с оттенка 100 градусов, и результат 99.76471. Интересно, почему существует (на мой взгляд) относительно большая неточность.

Но гораздо большая проблема заключается в том, что при повторном добавлении этого значения в код новый результат снова уменьшается.

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

Если начато с 99.76471, я получаю 99.52941. Для меня это проблема. Я сделал что-то подобное в java с классом «java.awt.Color», где у меня не было этих проблем. К сожалению, я не могу использовать этот класс в android.

+0

I * believe * это случай другого преобразования, используемого между 16 и 32-битным целым числом, однако это может быть отключено. Я помню несколько лет назад, столкнувшись с проблемой со звуковыми файлами и преобразованием из массива байтов. В конце концов я только округлял фигуру до ближайшего целого int. – dave

+1

Я поддерживаю идею дэйва. Одна вещь, которая может быть полезна, состоит в том, чтобы заметить, что разница между исходным значением 100 и округленным результатом 99.76471 равна 60/255, а 255 = 2^8-1 (довольно часто для хранения значений rgb на 8 бит) , То же самое верно для 99.76471 и 99.52941. У меня нет полной теории, но похоже, что основная арифметика пошла не так. – elias

ответ

1

Это интересная проблема. Этого нельзя избежать с классом android из-за низкой точности поплавка. Тем не менее, я нашел аналогичное решение, написанное на javascript here.

Если это достаточно важно, чтобы вы хотите, чтобы определить свой собственный метод/класс, чтобы делать преобразование, здесь является преобразованием Java, которая должна дать вам более высокую точность:

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

Я должен признаться, невежество здесь - Я сделал быстрое преобразование и не успел проверить правильно. Возможно, будет более оптимальное решение, но это должно заставить вас начать хотя бы.

+0

Ну, похоже, что более точный double не решает мою проблему, потому что он все еще округляется до int, и может возникнуть проблема, что я не получаю то же значение обратно – user2957782

Смежные вопросы