Я пытаюсь преобразовать цвет rgb в hsl на Java, я искал много кодов, объясняющих, как преобразовать rgb в hsl, теперь у меня работают насыщенность и яркость, но значение оттенка неверно
Я сейчас пытаюсь преобразовать rgb в hsl, а затем обратно.
значения rgb, которые я использую,
красный: 54 зеленый: 43 синий: 21
Значения hsl, которые я получаю,
оттенок: 260 насыщенность: 44 легкость: 15
Я попытался преобразовать значения rgb в hsl на https://www.rapidtables.com/convert/color/rgb-to-hsl.html
Значения, которые я получаю,
оттенок: 40 насыщенность: 44,0 легкость: 14,7
Кто-нибудь знает, что я делаю неправильно при преобразовании rgb в hsl? Вот мой код
public static Map<String, Integer> rgbToHsl(Integer red, Integer green, Integer blue){
Float redDouble = ((float)red) / 255.0f;
Float greenDouble = ((float)green) / 255.0f;
Float blueDouble = ((float)blue) / 255.0f;
Float max = Math.max(Math.max(redDouble, greenDouble), blueDouble);
Float min = Math.min(Math.min(redDouble, greenDouble), blueDouble);
Float chroma = max - min;
Float hue = chroma == 0.0f ? 0.0f :
(max == redDouble ? (greenDouble - blueDouble) / chroma :
(max == greenDouble ? 2f + (blueDouble - redDouble) / chroma :
4f + (redDouble - greenDouble) / chroma));
Float lightness = (max + min) * 0.5f;
Float saturation = chroma == 0.0f ? 0.0f : (lightness > 0.5f ? chroma / (2.0f - max - min) : chroma / (max + min));
return Map.ofEntries(
Map.entry("hue", (int) Math.round(hue * 60)),
Map.entry("saturation", (int) Math.round(saturation * 100)),
Map.entry("lightness", (int) Math.round(lightness * 100))
);
}
извините, я не понимаю, что вы подразумеваете под поплавками в штучной упаковке
Я думал, что это нужно было добавить, но я думаю, что нет
Теперь я помню, я сначала использовал двойные числа, а затем выдало ошибку, если я не преобразовал их в двойные
Возможно, будет полезно сравнить вашу реализацию с этой реализацией из Apache Commons. Еще лучше: просто используйте какую-нибудь стандартную библиотеку, где это уже реализовано.
Проверьте HSL Color для многоразового класса.
Что касается Float
: вы не используете примитивный тип с плавающей запятой float
, вы используете объекты в штучной упаковке Float
. Это не только снижает производительность, но и делает поведение ==
менее очевидным. Например, вы сравниваете их с ==
, что может привести к всевозможным «забавным» результатам, например Float a = new Float(0.0); Float b = new Float(0.0); System.out.println(a == b);
отдавать false
.
Итак, я должен использовать float
вместо Float
?
Это решило проблему, спасибо
Либо так, либо использование .equals(...)
в позициях, где поведение ==
неочевидно. Например, я мог представить, что max == redDouble
и max == greenDouble
всегда дают false
.
Для значения оттенка, если красный является максимальным, вы забыли преобразовать его по модулю 6.
Согласно тому, что показывает мне IntelliJ, он не верит, что max == redDouble даже при том, что их напечатанные значения выглядят одинаково. Итак, ваша вложенная логика для оттенка вычисляет неправильную часть. Я предлагаю вам написать некоторую логику, чтобы выяснить, ищете ли вы белый, красный, зеленый или синий цвет в виде строки, а затем использовать блок переключателей с новой цветовой строкой в качестве триггера, чтобы решить, какое значение вернуть. Это будет длиннее, но, вероятно, более читабельно. Хотя я поклонник тернарного оператора, их вложение может вызвать путаницу.
Спасибо за ответ, это часть проблемы, но я все еще получаю те же результаты, поэтому красный цвет в этом случае не был максимальным.
Я только что заметил! Логика в пользу синего отклика, хотя красный больше. Вернусь через мгновение.
Из одного из ответов выше я узнал, что проблема заключалась в использовании поплавков в штучной упаковке, спасибо за ответ.
Да, это несколько другой подход и, вероятно, более аккуратное решение. Спасибо за упражнение для мозга, рад, что вы разобрались :)
Нет проблем, я рад, что теперь все работает, и красный тоже правильно вычисляется.
Когда вы везде используете упакованные Float
, Math.max(Math.max(a, b), c)
распаковывает аргументы a
, b
и c
, затем выполняет вычисления, а затем упаковывает их обратно в Float
.
В результате получится новый объект, не равный всем трем a
, b
и c
.
Следовательно, сравнения тождеств max == redDouble
и max == greenDouble
всегда будут false
.
Исключите коробочные типы, используйте везде float
s, это и быстрее, и понятнее.
Еще лучше: никогда не используйте ни ==
, ни equals
для любых значений с плавающей запятой. Посмотрите, например, как здесь использовались дополнительные логические флаги. Логические значения не подвержены малейшим ошибкам округления.
Может быть, обо всем по порядку. Для чего нужны все коробки
Float
?