Detect main colors in an image with PHP

JasonDavis picture JasonDavis · Apr 24, 2012 · Viewed 47.6k times · Source

I am trying to replicate the functionality that Dribbble.com does with detecting the predominant colors in an Image. In the image below you can see a screenshot from Dribbble.com that shows the 8 predominant colors in the image to the left. Here is the actual page in the image http://dribbble.com/shots/528033-Fresh-Easy?list=following

I need to be able to do this in PHP, once I get the colors I need I will save them to a database so the processing does not need to be run on every page load.

After some research on how to get these colors out of an Image, some people said you simply examine an image pixel by pixel and then save the colors that occur the most. Other say there is more to it and that getting the colors that exist the most frequent won't give the desired affect. They say you need to Quantize the image/colors (I am lost at this point).

In the image below the Dribble shot below is a Javascript library that does the same thing, that page can be viewed here http://lokeshdhakar.com/projects/color-thief/

Viewing the source of that page I can see there is a Javascript file named quantize.js and the results are really good. So I am hoping to be able to do what that Javascript library does but with PHP and GD/ImageMagick

enter image description here


I had found this function that will return the colors and count in an Image with PHP but the results are different from the Javascript version above and the Dribble results

/**
 * 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)");
}

So I am asking if anyone knows how I can do such a task with PHP? Possibly something exist already that you know of or any tips to put me a step closer to doing this would be appreciated

Answer

Epoc picture Epoc · Feb 18, 2014

Here's exactly what you're looking for in PHP: https://github.com/thephpleague/color-extractor

Example :

use League\ColorExtractor\Palette;

$palette = Palette::fromFilename('some/image.png');

$topEightColors = $palette->getMostUsedColors(8);