Сочность картинки: как работает Vibrance, и готовый скрипт

В фотошопе появилась функция Vibrance, а в русской версии она называется «вибрация» или «сочность». Похожая вещь реализована и в современных смартфонах в режиме редактирования фото. Новый фильтр даёт более реалистичный результат на фотографиях. Это отличная замена топорному Saturation.

Напомню, классический фильтр Saturation поднимает насыщенность у каждого пикселя на фотографии, в итоге появляются области, «перекрученные по цветам». А кроме того, в JPEG изображении подчёркиваются артефакты:

Слева обычная фотка, справа — с задранной насыщенностьюСлева обычная фотка, справа — с задранной насыщенностью

Большинство фотографий в интернете на данный момент — именно в формате JPG среднего качества. Дополнительные преобразования могут ещё сильнее ухудшить внешний вид. Особенно это важно для товаров в интернет-магазинах. Поэтому любые подобные фильтры графики надо применять с осторожностью. И в этом смысле фильтр Vibrance — просто находка для интернет-магазинов, потому что он работает «умно».

Фильтр Vibrance поднимает насыщенность только в тех областях фото, где это действительно необходимо:

Слева обычная фотка, справа — с увеличенной сочностьюСлева обычная фотка, справа — с увеличенной сочностью

Что круче: Saturation или Vibrance?

Сравним результаты работы обоих фильтров. Левая фотка ужасна, а правая фотография стала более сочной, и при этом не утратила естественности. На левой фотке серый цвет превратился в коричневый и пошёл пятнами. На правой фотке серый цвет остался серым, а красная ткань сохранила текстуру и объём.

Сравнение фильтров Saturation (насыщенность) и Vibrance (сочность)Сравнение фильтров Saturation (насыщенность) и Vibrance (сочность)

Принцип работы алгоритма

По моим наблюдениям, Vibrance не действует:

1) На пиксели с большой насыщенностью
Зачем перенасыщать и без того красивые цвета?

2) На «нейтральных» пиксели с малой насыщенностью
Потому что эти цвета могут сильно исказиться.

Если у «нейтральных» цветов сильно перекрутить насыщенность, то они превратятся в совершенно другие цвета. Например, серый цвет в естественных природных условиях имеет лёгкий цветной оттенок, который «вылезет» наружу при сильном повышении насыщенности:

А цвет слоновой кости превратится в ярко-жёлтый:

Теперь становится понятно, почему хороший фильтр не должен касаться этих цветов.

А вот области средней насыщенности и освещённости — это те места, где можно разгуляться, добавить жизни этим цветам 😃

Реализация алгоритма

Перейду сразу к графикам. Слева график формулы y=x. Так выглядит график «нулевого» преобразования, когда на выходе — то же самое, что и на входе. Если пропустить картинку через этот фильтр, то ничего не изменится. На центральном графике — та самая надбавка, которая имеет максимальный пик в середине. В качестве надбавки я взял формулу обычного гауссовского распределения, только подобрал подходящие коэффициенты, чтобы результат не выходил за пределы единицы. Теперь, если сложить первый график со вторым, мы получим преобразование, которое затронет только среднюю область, при х от 0,25 до 0,75:

И вот такую картинку даёт данная формула:

Не обращайте внимания на зелёные точки 😃 Это косяки графической библиотеки PHP, будем считать это фишкой и защитой от копирования 😃

Вместо нормального распределения можно использовать любую похожую формулу. Давайте не будем всё усложнять, а сделаем линейные приближения, и сравним получаемые картинки, они под графиками:

Линейные преобразования насыщенностиЛинейные преобразования насыщенности
Средняя картинка — то, что надоСредняя картинка — то, что надо

Влияние яркости пикселя

Введём коэффициент KL, который будет зависеть от яркости. Пусть при L=50% наша формула имеет максимальную силу. А ближе к 0% или к 100% — ослабевает. Вот такой график KL получается:

С учётом яркости получается красивый результат, близкий к фотошоповскому:

Перейдём к написанию скрипта

Чтобы создать аналог функции Vibrance в PHP, Javascript или любом другом языке, потребуются следующие шаги:
1) прочитать файл картинки;
2) перебрать в цикле каждый пиксель картинки;
3) перевести цветовую модель пикселя из RGB в HSL;
4) увеличить S (Saturation) при помощи некоторой функции ƒ(S,L);
5) перевести цвет пикселя обратно в RGB;
6) вывести или сохранить готовую картинку.

Особого внимания достойна функция vibrance($S,$L). А остальные функции и весь код целиком можно найти в конце заметки.

PHP аналог функции Vibrance

function vibrance($S,$L) {
$kL=1-2*abs($L-0.5);
$S+=(0.5-abs($S-0.5))*$kL;

//$S+=0.3*pow(20,-pow($S-0.5,2)*5);
//$S+=0.5-abs($S-0.5);
//$S=$S/1.5+0.333333;
//$kL=1-2*abs($L-0.5);

return $S;
}

Если вы прочитали заметку, то тут всё понятно: сначала рассчитывается коэффициент $kL, который зависит от яркости. Затем насыщенность $S увеличивается на некоторую величину, помноженную на коэффициент $kL. Выбранный мною способ активен, а остальные варианты закомментированы.

Обычные функции — чтение, запись файла, а также преобразования цветовых моделей RGB↔HSL — легко находятся в интернете, и не требуют комментариев 😃

Вот скрипт целиком. Он на PHP, но вы без труда переведёте его на любой другой язык:

function RGB2HSL($r,$g,$b) {
$oldR=$r; $oldG=$g; $oldB=$b; $r/=255; $g/=255; $b/=255;
$max=max($r,$g,$b); $min=min($r,$g,$b);
$l=($max+$min)/2; $d=$max-$min;
if($d==0) {$h=$s=0;} else {
$s=$d/(1-abs(2*$l-1));
switch($max) {
case $r:
$h=60*fmod((($g-$b)/$d),6);
if($b>$g) {$h+=360;} break;
case $g:
$h=60*(($b-$r)/$d+2); break;
case $b:
$h=60*(($r-$g)/$d+4); break;
}
}
return array(round($h,3),round($s,3),round($l,3));
}

function HSL2RGB($h,$s,$l) {
$c=(1-abs(2*$l-1))*$s;
$x=$c*(1-abs(fmod(($h/60),2)-1));
$m=$l-($c/2);
if($h<60) {
$r=$c; $g=$x; $b=0;
} else if($h<120) {
$r=$x; $g=$c; $b=0;
} else if ($h<180) {
$r=0; $g=$c; $b=$x;
} else if($h<240) {
$r=0;
$g=$x;
$b=$c;
} else if ($h<300) {
$r=$x; $g=0; $b=$c;
} else {
$r=$c; $g=0; $b=$x;
}
$r=($r+$m)*255; $g=($g+$m)*255; $b=($b+$m)*255;
return array(floor($r),floor($g),floor($b));
}

function vibrance($S,$L) {
$kL=1-2*abs($L-0.5);
$S+=(0.5-abs($S-0.5))*$kL;

return $S;
}

$img=imagecreatefromjpeg("in.jpg");
$width=imagesx($img);
$height=imagesy($img);

for($y=0;$y<$height;$y++) {
for($x=0;$x<$width;$x++) {

$rgb=ImageColorAt($img,$x,$y);
$R=($rgb>>16) & 0xFF;
$G=($rgb>>8) & 0xFF;
$B=$rgb & 0xFF;

list($H,$S,$L)=RGB2HSL($R,$G,$B);

$S=vibrance($S,$L);

list($R,$G,$B)=HSL2RGB($H,$S,$L);

$color=imagecolorallocate($img,$R,$G,$B);
imagesetpixel($img,$x,$y,$color);

}
}

header("Content-Type: image/png");
imagepng($img);
imageDestroy($img);

Скачать скрипт Vibrance

📅 20 марта#PHP#урок#фото

Благодарность автору

Перевод через Яндекс.Деньги:

Смотрите также

Спонсоры поста

Комментарии

Дальнейшие комментарии временно закрыты. По всем вопросам обращайтесь ко мне по почте, через Вотсап или Вконтакте, см. раздел Контакты

© 2019