Изменить "насыщенность" изображения с помощью библиотеки PHP GD?

Существует отличный ответ о том, как изменить HUE изображения с помощью библиотеки PHP-GD. Но мне нужно знать, как изменить насыщенность изображения с помощью PHP-GD. Вот копия кода из ответа, который успешно меняет оттенок изображения.

function imagehue(&$image, $angle) {
    if($angle % 360 == 0) return;
    $width = imagesx($image);
    $height = imagesy($image);

    for($x = 0; $x < $width; $x++) {
      for($y = 0; $y < $height; $y++) {
        $rgb = imagecolorat($image, $x, $y);
        $r = ($rgb >> 16) & 0xFF;
        $g = ($rgb >> 8) & 0xFF;
        $b = $rgb & 0xFF;            
        $alpha = ($rgb & 0x7F000000) >> 24;
        list($h, $s, $l) = rgb2hsl($r, $g, $b);
        $h += $angle / 360;
        if($h > 1) $h--;
        list($r, $g, $b) = hsl2rgb($h, $s, $l);            
        imagesetpixel($image, $x, $y, imagecolorallocatealpha($image, $r, $g, $b, $alpha));
        }
    }
}

Если вам нужно взглянуть на код вспомогательных функций rgb2hsl а также hsl2rgb пожалуйста, проверьте оригинальный ответ. поскольку Hue является одним из параметров HSL, я думал, что мог бы как-то изменить функцию, чтобы получить рабочее решение для насыщения. Несмотря на ограниченные навыки php, мне пришлось попробовать, но это не сработало и дало странные результаты. Вот модификация, которую я пробую.


ИЗМЕНЕННЫЙ КОД: ОБНОВЛЕНО в соответствии с предложением @mark

function imageSaturation(&$image, $saturationPercentage) {
    $width = imagesx($image);
    $height = imagesy($image);

    for($x = 0; $x < $width; $x++) {
        for($y = 0; $y < $height; $y++) {
            $rgb = imagecolorat($image, $x, $y);
            $r = ($rgb >> 16) & 0xFF;
            $g = ($rgb >> 8) & 0xFF;
            $b = $rgb & 0xFF;            
            $alpha = ($rgb & 0x7F000000) >> 24;
            list($h, $s, $l) = rgb2hsl($r, $g, $b);         
            $s = $s * (100 + $saturationPercentage ) /100;
            if($s > 1) $s = 1;
            list($r, $g, $b) = hsl2rgb($h, $s, $l);            
            imagesetpixel($image, $x, $y, imagecolorallocatealpha($image, $r, $g, $b, $alpha));
        }
    }
}

header('Content-type: image/png');
$image = imagecreatefrompng('rgb.png');
imageSaturation($image, -80);//bring down current image saturation to 80%
imagepng($image);

ОБНОВЛЕНИЕ УСИЛИЯ: @Dai указал мне, что эти линии помогают создать цветовой код отдельного пикселя RGB. Значит, эта часть может остаться без изменений?

$rgb = imagecolorat($image, $x, $y);
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;            
$alpha = ($rgb & 0x7F000000) >> 24;

В следующей строке мы просто конвертируем значения RGB в HSL с помощью rgb2hsl($r, $g, $b); и назначив его list($h, $s, $l), Дело в том, что я застрял на данный момент, эти строки.

$s += $saturationPercentage / 100;
if($s > 1) $s--;

Я понимаю синтаксис, но не уверен, как я справлюсь с этим или если они даже требуются. Если бы не ответ полезные советы / предложения, было бы здорово. Я пытаюсь код на этом изображении снизить насыщенность со 100% до 80%, но в результате я получаю это изображение.

2 ответа

Решение

Я думаю, что вам нужно что-то вроде

$s=$s * (100+$saturationPercentage)/100 

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

Кроме того, если вы уменьшаете 1, если ваша новая насыщенность превышает 1, вам, вероятно, лучше будет установить ее на 1,0, то есть полностью насыщенную, например:

if($s>1)$s=1

в противном случае, скажем, результирующая насыщенность равна 1,3 (т.е. очень, очень насыщенная), вы сделаете это в 0.3т.е. очень ненасыщенный, вместо 1,0 (полностью насыщенный).

Так что если $s 0,7, и вы добавите 10%, вы получите

$s = 0.7 * (100 + 10)/100
$s = 0.7 * 1.1
$s = 0.77

Существует гораздо более простое и быстрое решение для уменьшения насыщенности цвета:

  • создать черно-белый клон изображения
  • смешать черно-белый клон с оригиналом

Код примерно такой:

      function imageSaturation($im, $percentage) /* $percentage to be between 0 and 100 */
{
    $width  = imagesx($im);
    $height = imagesy($im);     
    $im2  = imagecreatetruecolor($width, $height);
    imagecopy($im2, $im, 0, 0, 0, 0, $width, $height);
    imagefilter($im2, IMG_FILTER_GRAYSCALE);
    imagecopymerge($im, $im2, 0, 0, 0, 0, $width, $height, 100-$percentage);
    imagedestroy($im2);
}
Другие вопросы по тегам