Blog. Just Blog

Определение ближайшего цвета в палитре на PHP

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Web-мастеру и не только | Автор: ManHunter
Определение ближайшего цвета в палитре на PHP
Определение ближайшего цвета в палитре на PHP

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

Сразу оговорюсь, что в приведенном примере палитра создается из фиксированных значений, поэтому градиентные участки изображения могут получаться с заметными артефактами. В реальности надо брать палитру исходного изображения и работать уже с ней, считать количество точек каждого цвета, максимально объединять темные цвета, учитывать "кожаные" цвета, а также другие параметры. На специализированных ресурсах по графике наверняка есть более толковые статьи по оптимизации палитры. В остальном алгоритм оптимизации самого изображения будет таким же.
  1. $file='demo.jpg';
  2.  
  3. // Файл для обработки
  4. $im=ImageCreateFromJPEG($file);
  5.  
  6. // Размеры изображения
  7. $width=ImageSX($im);
  8. $height=ImageSY($im);
  9.  
  10. $new_image=ImageCreateTruecolor($width$height);
  11.  
  12. // Массив цветов в палитре
  13. $colors=array();
  14. for($c1=0$c1<=0xFF$c1+=0x11) {
  15.     for($c2=0$c2<=0xFF$c2+=0x11) {
  16.         for($c3=0$c3<=0xFF$c3+=0x11) {
  17.             $colors[]=array($c1,$c2,$c3);
  18.         }
  19.     }
  20. }
  21.  
  22. // Массив кэшированных цветов
  23. $best_keys=array();
  24.  
  25. for ($x=0$x<$width$x++) {
  26.     for ($y=0$y<$height$y++) {
  27.         $rgb=ImageColorAt($im,$x,$y);
  28.  
  29.         if (isset($best_keys[$rgb])) {
  30.             $best_key=$best_keys[$rgb];
  31.         }
  32.         else {
  33.             $R=($rgb >> 16) & 0xFF;
  34.             $G=($rgb >> 8) & 0xFF;
  35.             $B=$rgb 0xFF;
  36.  
  37.             $phi_min=1000000;
  38.             $best_key=0;
  39.  
  40.             // Найти ближайший цвет в палитре
  41.             foreach($colors as $key=>$value) {
  42.                 $phi=30*pow(($value[0]-$R),2)
  43.                     +59*pow(($value[1]-$G),2)
  44.                     +11*pow(($value[2]-$B),2);
  45.  
  46.                 if ($phi<$phi_min) {
  47.                     $phi_min=$phi;
  48.                     $best_key=$key;
  49.                 }
  50.             }
  51.  
  52.             // Сохранить найденный цвет в кэше
  53.             $best_keys[$rgb]=$best_key;
  54.         }
  55.  
  56.         $new_color=ImageColorAllocate($new_image,
  57.             $colors[$best_key][0],
  58.             $colors[$best_key][1],
  59.             $colors[$best_key][2]
  60.         );
  61.  
  62.         ImageSetPixel($new_image,$x,$y,$new_color);
  63.     }
  64. }
  65.  
  66. header("Content-type: image/png");
  67. ImagePNG($new_image,NULL);
  68.  
  69. // Прибраться за собой
  70. ImageDestroy($im);
  71. ImageDestroy($new_image);
Для каждой точки изображения считается различие ее цвета с каждым цветом из палитры. Коэффициенты 30, 59 и 11 отражают различную чувствительность человеческого глаза к красному, зеленому и синему цветам соответственно. Тот цвет из палитры, который будет меньше всего отличаться от цвета точки, и будет использоваться для нового изображения.

Узкое место в этом обработчике - тройной вложенный цикл поиска цвета для каждой точки. Частично это сглаживается путем кэширования уже обработанных цветов, но для больших картинок время обработки все равно будет очень продолжительным. Имейте это в виду, если будете использовать код на реальных проектах.

Эффект "cartoon-изации"
Эффект "cartoon-изации"

При уменьшении количества цветов в палитре получается эффект "cartoon-изации", то есть превращение фотографии в рисованный кадр, примерно как в комиксах или мультфильмах. Но тут качество готового изображения также очень сильно зависит от правильно подобранной палитры.

Поделиться ссылкой ВКонтакте
Просмотров: 1164 | Комментариев: 3

Метки: PHP, графика
Внимание! Статья опубликована больше года назад, информация могла устареть!

Комментарии

Отзывы посетителей сайта о статье
User (25.05.2021 в 05:40):
Заинтересовался, ссылка в тему. Правда по ffmpeg, но теория - всегда интересно ) http://blog.pkh.me/p/21-high-q...-ffmpeg.html
ManHunter (23.05.2021 в 20:25):
На PHP программирование не заканчивается, а вот алгоритм остается.
wet (22.05.2021 в 15:07):
GIF формат подобно делает, сжатые данные без потери качества в формате не более 256 цветов. Думаю конвертер Изображение-> GIF на PHP точно есть, типа такого:
$rez=ImageCreateFromJpeg("23.jpg");
imagegif($rez,"23.gif");

Добавить комментарий

Заполните форму для добавления комментария
Имя*:
Текст комментария (не более 2000 символов)*:

*Все поля обязательны для заполнения.
Комментарии, содержащие рекламу, ненормативную лексику, оскорбления и т.п., а также флуд и сообщения не по теме, будут удаляться. Нарушителям может быть заблокирован доступ к сайту.
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2025
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.07 сек. / MySQL: 2 (0.0066 сек.) / Память: 4.5 Mb
Наверх