C ++: настройка HSL изображения без отсечения

Я пытаюсь запрограммировать фильтр Hue / Saturation / Lightness для изображения (в C ++). Преобразования RGB-> HSL работают нормально, но моя проблема возникает при учете того факта, что каждый пиксель имеет различную начальную насыщенность и яркость.

Для каждого пикселя я рассчитал исходный HSL и получил значения HSL в качестве входных данных фильтра (в диапазоне [0, 1]). Я хотел бы сделать 0,5 по умолчанию для всех (выходной сигнал совпадает с входным), 0,0 для насыщенности означает оттенки серого или полностью черный для яркости, а 1,0 означает полностью насыщенные или полностью белые. В отличие от насыщенности и яркости, часть оттенка проста: просто добавьте и оберните в диапазоне [0, 1].

Тогда возникает задача: как мы преобразуем значения насыщенности и яркости каждого пикселя на основе входных данных фильтра?

Одно решение, которое пришло на ум:

Out.H = Wrap(In.H + Filter.H - 0.5f, 0.0f, 1.0f);
Out.S = std::clamp(In.S * Filter.S * 2.0f, 0.0f, 1.0f);
Out.L = std::clamp(In.L * Filter.L * 2.0f, 0.0f, 1.0f);

куда Out это выход, In является исходным изображением, и Filter это настройки фильтра. Но если исходное изображение сильно контрастирует с ним, первоначально светлые части изображения быстро обрезаются (фиксируются на сплошной 1,0f), теряя детализацию, в то время как более темные части могут быть едва заметны. Так что вместо этого я подумал, что, возможно, будут некоторые кривые, которые можно применить к нему, которые предотвратят это отсечение, при этом позволяя 0.5f вернуть исходное значение. Я подумал об использовании функции мощности и расчета необходимой мощности. Я придумал:

f(x) = x ^ log_1/2(a)

куда a это значение на входном пикселе (значение функции при x = 0.5f). Например:
f (x) = x ^ log_1 / 2 (.2)

Эта функция, f(x) = x ^ log_1/2(0.2), проходит через (0,0), (0,5, 0,2) и (1, 1). Таким образом, если бы насыщенность входного пикселя составляла 0,2f, а входной сигнал насыщенности фильтра от пользователя был равен x, то выполнение этой функции сработало бы. Вам нужно заменить 0.2 в функции на то, какой будет насыщенность входного пикселя. Предположительно, то же самое можно сделать для легкости. Таким образом, код становится:

Out.H = Wrap(In.H + Filer.H - 0.5f, 0.0f, 1.0f);
Out.S = pow(In.S, log(Filter.S) / log(0.5f));
Out.L = pow(In.L, log(Filter.L) / log(0.5f));

Это хорошо работает для изображений со средней насыщенностью и яркостью. Но, если он изначально очень высок или очень низок, этот подход может означать, что функция сбрасывается очень близко к 0 или 1. Например, если насыщенность изначально равна 0,97, функция выглядит следующим образом:

f (x) = x ^ log_1 / 2 (.97)

(С точкой в ​​(0.5, 0.97) я забыл отметить это).

Это означает, что вам придется уменьшить насыщенность до уровня, равного 0,001, прежде чем вы начнете видеть какую-либо фактическую разницу. Я столкнулся с этой проблемой с этим тестовым изображением:

Оригинал (насыщенность = 0,5):

Насыщенность = 0,001

Насыщенность = 0.0

На данный момент я застрял. Есть ли способ отрегулировать насыщенность и яркость, не теряя детали или отсечения? Возможно, есть другой метод изгиба, который можно использовать? Есть ли стандартный способ сделать это, что мне не удалось найти?
Заранее спасибо.

Графики сделаны с Desmos онлайн графический калькулятор.

1

Решение

Хорошо, я до сих пор не знаю ни одного «стандартного» способа достижения этой цели, но я обнаружил, что тригонометрические кривые работают относительно хорошо даже для сильно насыщенных изображений.

Используя две функции a*sin(x*PI) where {0 <= x <= 0.5} а также 1+(a-1)*sin(x*PI) where {.5 < x <= 1.0}можно создать кривые следующим образом:

Начальная насыщенность (a) = 0,2:

Триг 0.2

Начальная насыщенность = 0,97:

Триг 0,97

Код:

Out.H = Wrap(In.H + Filter.H - 0.5f, 0.0f, 1.0f);
Out.S = (Filter.S <= 0.5f) ? (In.S * sin(Filter.S * PI)) : (1.0f - (1.0f - In.S) * sin(Filter.S * PI));
Out.L = (Filter.L <= 0.5f) ? (In.L * sin(Filter.L * PI)) : (1.0f - (1.0f - In.L) * sin(Filter.L * PI));

Понятно, что это не идеально, но на данный момент кажется достаточным, и позволяет намного чище регулировать изображение, чем функция мощности. Это также означает, что разные пиксели теряют и набирают насыщенность с разной скоростью, чем раньше, возможно, иначе, чем большинство фильтров регулировки HSL. Если кто-то знает «стандартный» или обычный способ обращения с вещами, пожалуйста, поделитесь!

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]