Цвета палитры PHP GD

Как в PHP GD преобразовать изображение truecolor в палитру без потери ничего цвета. С imagetruecolortopallete это не работает. У меня есть функция, которая просматривает все цвета и фильтрует их (например, оттенки серого). и Он не сохраняет все цвета, как, например, на этом изображении Lamborghini-

Изображение

альтернативный текст

Это мой код

$im = imagecreatefrompng("lamborghini.png");
$degrees = 0;

$img = imagecreatetruecolor(imagesx($im), imagesy($im));
imagecopy($img, $im, 0, 0, 0, 0, imagesx($im), imagesy($im));
imagetruecolortopalette($img, true, 256);
$t = imagecolorstotal($img);
for ($i = 0; $i < $t; $i++) {
  $rgb = imagecolorsforindex($img, $i);
  $hsv =rgbtohsv($rgb['red'], $rgb['green'], $rgb['blue']);
  $h = $degrees;
  $s = $hsv['s'];
  $v = $hsv['v'];
  while ($h > 360) {$h -= 360;};
        $nrgb = hsvtorgb($h, $s, $v);
  imagecolorset($img, $i, $nrgb['r'], $nrgb['g'], $nrgb['b']);
}
imagecopy($im, $img, 0, 0, 0, 0, imagesx($img), imagesy($img));

header('Content-type: image/png');

imagepng($im);
imagedestroy($im);

И это выглядит так

альтернативный текст

Вы можете видеть цвет теряется. Есть ли какое-нибудь решение?

Также я не думаю, что это связано с моим кодом, но как imagetruecolortopalette выводит это


person Mark Lalor    schedule 16.09.2010    source источник
comment
Преобразование палитры в библиотеке GD выполняется быстро, но очень неточно. Если вы хотите использовать палитру, я рекомендую использовать командную строку pngquant через popen() — хотя это и потеряет некоторые цвета, потеря будет не такой серьезной.   -  person Kornel    schedule 03.12.2011


Ответы (3)


Проверьте возврат на imagecolorstotal, вы всегда получаете 256 цветов в качестве возврата, независимо от того, насколько высоко вы установили количество цветов для сглаживания. Форматы PNG-8 и GIF поддерживают только палитры до 256 цветов. Таким образом, даже если вы можете использовать более 256 цветов в палитре, вам придется сохранить их обратно как истинные цвета, чтобы каждый мог их использовать, что делает весь процесс преобразования пустой тратой времени. Другими словами, imagetruecolortopallete имеет верхний предел в 256 цветов, вы не можете подняться выше.

Вот как вы можете сделать это в истинном цвете, хотя это требует больших ресурсов. Возможно, посмотрите на imagemagick, если вы хотите сделать это более эффективно.

$im = imagecreatefrompng("lamb.png");
$img = imagecreatetruecolor(imagesx($im), imagesy($im));
$degrees = 0;
if ($degrees > 360) {$degrees = $degrees % 360 ;}

foreach (range(0, imagesx($im) - 1) as $x ) {
    foreach (range(0, imagesy($im) - 1) as $y) {
        $rgb = imagecolorat($im, $x, $y);
        $r = ($rgb >> 16) & 0xFF;
        $g = ($rgb >> 8) & 0xFF;
        $b = $rgb & 0xFF;
        $hsv = rgbtohsv($r,$g,$b);
        $rgb = hsvtorgb($degrees, $hsv['s'], $hsv['v']);
        imagesetpixel($img, $x,$y,imagecolorallocate($img, $rgb['r'], $rgb['g'], $rgb['b']));
    }
}

imagepng($img, 'lamb2.png');

Изменить: добавление функций rgbtohsv и hsvtorgb. Я не писал эти функции.

function rgbtohsv ($R, $G, $B) {
 // HSV Results:Number 0-1
$HSL = array();

$var_R = ($R / 255);
$var_G = ($G / 255);
$var_B = ($B / 255);

$var_Min = min($var_R, $var_G, $var_B);
$var_Max = max($var_R, $var_G, $var_B);
$del_Max = $var_Max - $var_Min;

$V = $var_Max;

if ($del_Max == 0)
{
$H = 0;
$S = 0;
}
else
{
$S = $del_Max / $var_Max;

$del_R = ( ( ( $var_Max  - $var_R ) / 6 ) + ( $del_Max / 2 ) ) / $del_Max;
$del_G = ( ( ( $var_Max  - $var_G ) / 6 ) + ( $del_Max / 2 ) ) / $del_Max;
$del_B = ( ( ( $var_Max  - $var_B ) / 6 ) + ( $del_Max / 2 ) ) / $del_Max;

if ($var_R == $var_Max) $H = $del_B - $del_G;
else if ($var_G == $var_Max) $H = ( 1 / 3 ) + $del_R - $del_B;
else if ($var_B == $var_Max) $H = ( 2 / 3 ) + $del_G - $del_R;

if ($H<0) $H++;
if ($H>1) $H--;
}

$HSL['h'] = $H;
$HSL['s'] = $S;
$HSL['v'] = $V;

return $HSL;
}

function hsvtorgb ($H, $S, $V) 
{
$RGB = array();

if($S == 0)
{
$R = $G = $B = $V * 255;
}
else
{
$var_H = $H * 6;
$var_i = floor( $var_H );
$var_1 = $V * ( 1 - $S );
$var_2 = $V * ( 1 - $S * ( $var_H - $var_i ) );
$var_3 = $V * ( 1 - $S * (1 - ( $var_H - $var_i ) ) );

if ($var_i == 0) { $var_R = $V ; $var_G = $var_3 ; $var_B = $var_1 ; }
else if ($var_i == 1) { $var_R = $var_2 ; $var_G = $V ; $var_B = $var_1 ; }
else if ($var_i == 2) { $var_R = $var_1 ; $var_G = $V ; $var_B = $var_3 ; }
else if ($var_i == 3) { $var_R = $var_1 ; $var_G = $var_2 ; $var_B = $V ; }
else if ($var_i == 4) { $var_R = $var_3 ; $var_G = $var_1 ; $var_B = $V ; }
else { $var_R = $V ; $var_G = $var_1 ; $var_B = $var_2 ; }

$R = $var_R * 255;
$G = $var_G * 255;
$B = $var_B * 255;
}

$RGB['r'] = $R;
$RGB['g'] = $G;
$RGB['b'] = $B;

return $RGB;
}
person Klinky    schedule 17.09.2010
comment
что такое rgbtohsv и hsvtorgb - person EscoMaji; 23.02.2012
comment
@EscoMaji Я добавил эти функции в пост. - person Klinky; 23.02.2012

преобразование истинного цвета в палитру всегда будет связано с потерей цветов, если только ваша таблица палитр не достаточно велика, чтобы вместить каждый уникальный цвет в изображении. Lamborghini вполне может иметь больше, чем, скажем, 255 оттенков желтого, и тогда вам все еще нужны слоты палитры для остальной части изображения вдобавок к этому. Вот почему есть полноцветные изображения. Здесь нет палитры, но каждый пиксель может иметь свой собственный выделенный триплет RGB для более точного представления исходной сцены.

При этом я не вижу, как преобразование изображения в истинном цвете изменит желтый цвет на красный, как в ваших образцах изображений. Как именно вы делаете это преобразование палитры? Выборка каждого пикселя и какое-то преобразование?

person Marc B    schedule 16.09.2010
comment
Что произойдет, если вы устраните rgb-›hsv-›rgb туда и обратно? Видите, что выдает палитра imagetruecolortop? Я предполагаю, что у вас есть ошибка в функции rgbtohsv и/или hsvtorgb, так как даже «плохой» генератор палитры не произведет столько красных из исходного изображения, в котором их нет. - person Marc B; 17.09.2010
comment
Нет, я решил проблему, опционально используя палитру (для скорости) и truecolor для качества. - person Mark Lalor; 17.09.2010

Как насчет этой функции: http://www.php.net/manual/en/function.imagetruecolortopalette.php. Однако, возможно, придется немного повозиться с количеством цветов, чтобы все получилось правильно.

person Chris Laplante    schedule 16.09.2010
comment
У вас включен dither? И сколько цветов вы указали? - person Chris Laplante; 17.09.2010
comment
Это то, что у меня есть imagetruecolortopalette($img, true, 256); так что да - person Mark Lalor; 17.09.2010
comment
Попробуйте увеличить количество цветов с 256, скажем, до 512. Если есть какое-либо улучшение, продолжайте увеличивать количество цветов, пока качество не станет приемлемым. - person Chris Laplante; 17.09.2010