Неверное преобразование rgb в оттенок

Я пытаюсь преобразовать цвет 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))
        );
    }

Может быть, обо всем по порядку. Для чего нужны все коробки Float?

Andrey Tyukin 12.12.2020 21:15

извините, я не понимаю, что вы подразумеваете под поплавками в штучной упаковке

Jaron 12.12.2020 21:16

Я думал, что это нужно было добавить, но я думаю, что нет

Jaron 12.12.2020 21:21

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

Jaron 12.12.2020 21:22

Возможно, будет полезно сравнить вашу реализацию с этой реализацией из Apache Commons. Еще лучше: просто используйте какую-нибудь стандартную библиотеку, где это уже реализовано.

Andrey Tyukin 12.12.2020 21:24

Проверьте HSL Color для многоразового класса.

camickr 12.12.2020 21:25

Что касается Float: вы не используете примитивный тип с плавающей запятой float, вы используете объекты в штучной упаковке Float. Это не только снижает производительность, но и делает поведение == менее очевидным. Например, вы сравниваете их с ==, что может привести к всевозможным «забавным» результатам, например Float a = new Float(0.0); Float b = new Float(0.0); System.out.println(a == b); отдавать false.

Andrey Tyukin 12.12.2020 21:31

Итак, я должен использовать float вместо Float?

Jaron 12.12.2020 21:32

Это решило проблему, спасибо

Jaron 12.12.2020 21:36

Либо так, либо использование .equals(...) в позициях, где поведение == неочевидно. Например, я мог представить, что max == redDouble и max == greenDouble всегда дают false.

Andrey Tyukin 12.12.2020 21:36
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
10
106
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

Согласно тому, что показывает мне IntelliJ, он не верит, что max == redDouble даже при том, что их напечатанные значения выглядят одинаково. Итак, ваша вложенная логика для оттенка вычисляет неправильную часть. Я предлагаю вам написать некоторую логику, чтобы выяснить, ищете ли вы белый, красный, зеленый или синий цвет в виде строки, а затем использовать блок переключателей с новой цветовой строкой в ​​качестве триггера, чтобы решить, какое значение вернуть. Это будет длиннее, но, вероятно, более читабельно. Хотя я поклонник тернарного оператора, их вложение может вызвать путаницу.

Спасибо за ответ, это часть проблемы, но я все еще получаю те же результаты, поэтому красный цвет в этом случае не был максимальным.

Jaron 12.12.2020 21:24

Я только что заметил! Логика в пользу синего отклика, хотя красный больше. Вернусь через мгновение.

sunrise 12.12.2020 21:28

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

Jaron 12.12.2020 21:37

Да, это несколько другой подход и, вероятно, более аккуратное решение. Спасибо за упражнение для мозга, рад, что вы разобрались :)

sunrise 12.12.2020 21:38

Нет проблем, я рад, что теперь все работает, и красный тоже правильно вычисляется.

Jaron 12.12.2020 21:40
Ответ принят как подходящий

Когда вы везде используете упакованные Float, Math.max(Math.max(a, b), c) распаковывает аргументы a, b и c, затем выполняет вычисления, а затем упаковывает их обратно в Float.

В результате получится новый объект, не равный всем трем a, b и c.

Следовательно, сравнения тождеств max == redDouble и max == greenDouble всегда будут false.

Исключите коробочные типы, используйте везде floats, это и быстрее, и понятнее.

Еще лучше: никогда не используйте ни ==, ни equals для любых значений с плавающей запятой. Посмотрите, например, как здесь использовались дополнительные логические флаги. Логические значения не подвержены малейшим ошибкам округления.

Другие вопросы по теме