Обнаружение основных цветов в изображении с помощью PHP

Я пытаюсь воспроизвести функциональность, которая Dribbble.com делает с обнаружением преобладающих цветов в изображении. На изображении ниже вы можете увидеть скриншот из Dribbble.com это показывает 8 преобладающих цветов на изображении слева. Вот фактическая страница в изображении http://dribbble.com/shots/528033-Fresh-Easy?list=following

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

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

на изображении ниже дриббла выстрел ниже Библиотека Javascript, которая делает то же самое, эту страницу можно просмотреть здесь http://lokeshdhakar.com/projects/color-thief/

просмотр источника этой страницы я вижу, что есть файл Javascript с именем quantize.js и результаты действительно хорошие. Поэтому я надеюсь, что смогу сделать то, что делает эта библиотека Javascript, но с PHP и GD/ImageMagick

enter image description here


Я нашел эту функцию, которая будет возвращать цвета и подсчет Изображение с PHP, но результаты отличаются от версии Javascript выше и результатов Dribble

/**
 * Returns the colors of the image in an array, ordered in descending order, where the keys are the colors, and the values are the count of the color.
 *
 * @return array
 */
function Get_Color()
{
    if (isset($this->image))
    {
        $PREVIEW_WIDTH    = 150;  //WE HAVE TO RESIZE THE IMAGE, BECAUSE WE ONLY NEED THE MOST SIGNIFICANT COLORS.
        $PREVIEW_HEIGHT   = 150;
        $size = GetImageSize($this->image);
        $scale=1;
        if ($size[0]>0)
        $scale = min($PREVIEW_WIDTH/$size[0], $PREVIEW_HEIGHT/$size[1]);
        if ($scale < 1)
        {
            $width = floor($scale*$size[0]);
            $height = floor($scale*$size[1]);
        }
        else
        {
            $width = $size[0];
            $height = $size[1];
        }
        $image_resized = imagecreatetruecolor($width, $height);
        if ($size[2]==1)
        $image_orig=imagecreatefromgif($this->image);
        if ($size[2]==2)
        $image_orig=imagecreatefromjpeg($this->image);
        if ($size[2]==3)
        $image_orig=imagecreatefrompng($this->image);
        imagecopyresampled($image_resized, $image_orig, 0, 0, 0, 0, $width, $height, $size[0], $size[1]); //WE NEED NEAREST NEIGHBOR RESIZING, BECAUSE IT DOESN'T ALTER THE COLORS
        $im = $image_resized;
        $imgWidth = imagesx($im);
        $imgHeight = imagesy($im);
        for ($y=0; $y < $imgHeight; $y++)
        {
            for ($x=0; $x < $imgWidth; $x++)
            {
                $index = imagecolorat($im,$x,$y);
                $Colors = imagecolorsforindex($im,$index);
                $Colors['red']=intval((($Colors['red'])+15)/32)*32;    //ROUND THE COLORS, TO REDUCE THE NUMBER OF COLORS, SO THE WON'T BE ANY NEARLY DUPLICATE COLORS!
                $Colors['green']=intval((($Colors['green'])+15)/32)*32;
                $Colors['blue']=intval((($Colors['blue'])+15)/32)*32;
                if ($Colors['red']>=256)
                $Colors['red']=240;
                if ($Colors['green']>=256)
                $Colors['green']=240;
                if ($Colors['blue']>=256)
                $Colors['blue']=240;
                $hexarray[]=substr("0".dechex($Colors['red']),-2).substr("0".dechex($Colors['green']),-2).substr("0".dechex($Colors['blue']),-2);
            }
        }
        $hexarray=array_count_values($hexarray);
        natsort($hexarray);
        $hexarray=array_reverse($hexarray,true);
        return $hexarray;

    }
    else die("You must enter a filename! ($image parameter)");
}

поэтому я спрашиваю, знает ли кто-нибудь, как я могу выполнить такую задачу с PHP? Возможно, что-то уже существует, что вы знаете, или любые советы, чтобы поставить меня на шаг ближе к этому, будут оценены

7 ответов


вот именно то, что вы ищете в PHP: https://github.com/thephpleague/color-extractor

пример :

require 'vendor/autoload.php';

use League\ColorExtractor\Client as ColorExtractor;

$client = new ColorExtractor;

$image = $client->loadPng('./some/image.png');

// Get the most used color hexadecimal codes from image.png
$palette = $image->extract();

Это мой простой метод, чтобы получить основной цвет изображения

<?php 

  $image=imagecreatefromjpeg('image.jpg');
  $thumb=imagecreatetruecolor(1,1); imagecopyresampled($thumb,$image,0,0,0,0,1,1,imagesx($image),imagesy($image));
    $mainColor=strtoupper(dechex(imagecolorat($thumb,0,0)));
  echo $mainColor;

?>

вам нужно уменьшить масштаб изображения, и вы получите основные цвета изображения. Если вам нужно 4 цвета в поддоне, уменьшите его до примерно 8x8, 6 цветов, чтобы о 12x8 и так далее...

imagecopyresized для уменьшенного изображения затем проверьте все пиксели и сохраните их в массиве imagecolorat($image,px,py)

попробуйте это

<?php

// EXAMPLE PICTURE
$url='https://www.nordoff-robbins.org.uk/sites/default/files/google.jpg';

//var_dump(getColorPallet($url));

echoColors(getColorPallet($url));


function echoColors($pallet){ // OUTPUT COLORSBAR
    foreach ($pallet as $key=>$val)
        echo '<div style="display:inline-block;width:50px;height:20px;background:#'.$val.'"> </div>';
}

function getColorPallet($imageURL, $palletSize=[16,8]){ // GET PALLET FROM IMAGE PLAY WITH INPUT PALLET SIZE
    // SIMPLE CHECK INPUT VALUES
    if(!$imageURL) return false;

    // IN THIS EXEMPLE WE CREATE PALLET FROM JPG IMAGE
    $img = imagecreatefromjpeg($imageURL);

    // SCALE DOWN IMAGE
    $imgSizes=getimagesize($imageURL);

    $resizedImg=imagecreatetruecolor($palletSize[0],$palletSize[1]);

    imagecopyresized($resizedImg, $img , 0, 0 , 0, 0, $palletSize[0], $palletSize[1], $imgSizes[0], $imgSizes[1]);

    imagedestroy($img);

    //CHECK IMAGE
    /*header("Content-type: image/png");
    imagepng($resizedImg);
    die();*/

    //GET COLORS IN ARRAY
    $colors=[];

    for($i=0;$i<$palletSize[1];$i++)
        for($j=0;$j<$palletSize[0];$j++)
            $colors[]=dechex(imagecolorat($resizedImg,$j,$i));

    imagedestroy($resizedImg);

    //REMOVE DUPLICATES
    $colors= array_unique($colors);

    return $colors;

}
?>

работает идеально для меня.


страница, на которую вы ссылаетесь, имеет ссылку на исходный код на GitHub, поэтому, если вы хотите точно знать, как они это делают, вы можете скопировать их источник в PHP.

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


попробуйте это: http://www.coolphptools.com/color_extract

работает с JPEG и PNG.

и лучше!: нет суеты с композитором, просто require_once

require_once 'colorextract/colors.inc.php';
$ex=new GetMostCommonColors();
$num_results=20;
$reduce_brightness=1;
$reduce_gradients=1;
$delta=24;
$colors=$ex->Get_Color( 'image.png', $num_results, $reduce_brightness, $reduce_gradients, $delta);
print_r($colors);

дать вам что-то вроде этого:

массив ( [3060a8] = > 0,55827380952381 [f0a848] = > 0,19791666666667 [000000] => 0.069642857142857 [483018] = > 0,02047619047619 [786018] = > 0,01827380952381 [183060] = > 0,01797619047619 [4878a8] = > 0,016011904761905 [181800] = > 0,015119047619048 [a87830] => 0,014345238095238 [a8c0d8] => 0,011904761904762 [6090c0] => 0,01172619047619 [d89030] => 0,011011904761905 [90a8d8] => 0.0071428571428571 [ffffff] => 0.0070238095238095 [604830] = > 0,006547619047619 [f0f0f0] => 0,0063095238095238 [d8d8f0] => 0,005297619047619 [c0d8d8] => 0,0044047619047619 [f0f0ff] => 0,00041666666666667 [181830] => 0.00011904761904762 )

Я пробовал это с разными изображениями, и это кажется надежным.


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

Я думаю, что алгоритм как вектор цветовой когерентности будет достаточно хорошо, чтобы преодолеть эту проблему, потому что он группирует цвета в когерентные и некогерентные (что довольно интуитивно), а затем вы можете использовать их, чтобы отбросить эти ложные положительные преобладающие цвета.

Я вижу, что это простой алгоритм для реализации, этот учебник извлечение изображения: вектор цветовой когерентности описывает описывает свои шаги с примерами, как это работает и есть даже matlab реализация, упомянутая в конце его.


У меня есть сценарий оболочки Unix bash с ImageMagick под названием dominantcolor, который может делать то, что вы хотите. См. мой веб-сайт скриптов по адресуhttp://www.fmwconcepts.com/imagemagick/index.php. Вы запускаете его из PHP exec (). Смотрите мои указатели для использования на моей домашней странице.

вход:

enter image description here

dominantcolor -n 6 -p all -s save plate.png

count,hexcolor
586,#5ECADC
520,#AFA85D
469,#3C3126
462,#B9C8BB
258,#488A70
205,#B06928


- n 6-желаемое количество цветов в цветовом квантовании. -P все означает печать всех подсчетов и цвета для итоговой 6 цветов. The-S save indictates для сохранения изображения образца.

цвета ниже показаны с доминирующим цветом слева и уменьшением количества цветов вправо в соответствии со списком выше.

enter image description here