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

Определение ближайшего цвета в палитре на PHP
Один из наиболее эффективных способов уменьшения размера картинок - оптимизация используемых цветов. При размере палитры в несколько десятков тысяч цветов, многие из оттенков отличаются настолько незначительно, что для человеческого глаза такая разница вообще незаметна. Оставив в палитре только оптимальные цвета, надо пройтись по изображению и заменить цвет каждой точки на ближайший цвет из палитры.
Сразу оговорюсь, что в приведенном примере палитра создается из фиксированных значений, поэтому градиентные участки изображения могут получаться с заметными артефактами. В реальности надо брать палитру исходного изображения и работать уже с ней, считать количество точек каждого цвета, максимально объединять темные цвета, учитывать "кожаные" цвета, а также другие параметры. На специализированных ресурсах по графике наверняка есть более толковые статьи по оптимизации палитры. В остальном алгоритм оптимизации самого изображения будет таким же.
Code (PHP) : Убрать нумерацию
- $file='demo.jpg';
- // Файл для обработки
- $im=ImageCreateFromJPEG($file);
- // Размеры изображения
- $width=ImageSX($im);
- $height=ImageSY($im);
- $new_image=ImageCreateTruecolor($width, $height);
- // Массив цветов в палитре
- $colors=array();
- for($c1=0; $c1<=0xFF; $c1+=0x11) {
- for($c2=0; $c2<=0xFF; $c2+=0x11) {
- for($c3=0; $c3<=0xFF; $c3+=0x11) {
- $colors[]=array($c1,$c2,$c3);
- }
- }
- }
- // Массив кэшированных цветов
- $best_keys=array();
- for ($x=0; $x<$width; $x++) {
- for ($y=0; $y<$height; $y++) {
- $rgb=ImageColorAt($im,$x,$y);
- if (isset($best_keys[$rgb])) {
- $best_key=$best_keys[$rgb];
- }
- else {
- $R=($rgb >> 16) & 0xFF;
- $G=($rgb >> 8) & 0xFF;
- $B=$rgb & 0xFF;
- $phi_min=1000000;
- $best_key=0;
- // Найти ближайший цвет в палитре
- foreach($colors as $key=>$value) {
- $phi=30*pow(($value[0]-$R),2)
- +59*pow(($value[1]-$G),2)
- +11*pow(($value[2]-$B),2);
- if ($phi<$phi_min) {
- $phi_min=$phi;
- $best_key=$key;
- }
- }
- // Сохранить найденный цвет в кэше
- $best_keys[$rgb]=$best_key;
- }
- $new_color=ImageColorAllocate($new_image,
- $colors[$best_key][0],
- $colors[$best_key][1],
- $colors[$best_key][2]
- );
- ImageSetPixel($new_image,$x,$y,$new_color);
- }
- }
- header("Content-type: image/png");
- ImagePNG($new_image,NULL);
- // Прибраться за собой
- ImageDestroy($im);
- ImageDestroy($new_image);
Узкое место в этом обработчике - тройной вложенный цикл поиска цвета для каждой точки. Частично это сглаживается путем кэширования уже обработанных цветов, но для больших картинок время обработки все равно будет очень продолжительным. Имейте это в виду, если будете использовать код на реальных проектах.

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

Внимание! Статья опубликована больше года назад, информация могла устареть!
Комментарии
Отзывы посетителей сайта о статье
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");
$rez=ImageCreateFromJpeg("23.jpg");
imagegif($rez,"23.gif");

Добавить комментарий
Заполните форму для добавления комментария
