Detect main colors in an image with PHP

54,864

Solution 1

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);

Solution 2

This is my simple method to get the main color of an image

$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;

Solution 3

You need to scale down the picture and you will get the main colors of the picture. If you need 4 colors in the pallet, scale it down to about 8x8, 6 colors to about 12x8 and so on...

imagecopyresized for scaled down image then check every pixels and store them in array imagecolorat($image,px,py)

Try this out

<?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;

}
?>

Works perfect for me.

Solution 4

The page you linked to has a link to the source code on GitHub so if you want to know exactly how they are doing you could replicate their source in PHP.

The big difference between how they are doing it and how you are doing it, is that they are using clustering to find the color. Instead of rounding the color when they store it, they are storing all of the raw colors in an array. Then they loop through this array until they find a cluster that has the highest ratio of points in the cluster to number of colors in the cluster. The center point of this is the most common color. The palette is then defined by the next highest sets of clusters, with some logic to prevent near complete overlap of the clusters.

Solution 5

Try this: http://www.coolphptools.com/color_extract

Works with JPEG and PNG.

And best!: no hustle with composer, just 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);

give you something like this:

Array ( [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 )

I tried it with different images and it seems reliable.

Share:
54,864
JasonDavis
Author by

JasonDavis

PHP/MySQL is my flavor of choice however more recently JavaScript is really becoming something I enjoy developing with! Writing code since 2000' Currently working heavily with SugarCRM + Launching my Web Dev company ApolloWebStudio.com "Premature optimization is not the root of all evil, lack of proper planning is the root of all evil." Twitter: @JasonDavisFL Work: Apollo Web Studio - https://www.apollowebstudio.com Some of my Web Dev skills, self rated... +------------+--------+------+--------------+ | Skill | Expert | Good | Intermediate | +------------+--------+------+--------------+ | PHP | X | | | +------------+--------+------+--------------+ | MySQL | X | | | +------------+--------+------+--------------+ | Javascript | X | | +------------+--------+------+--------------+ | jQuery | X | | +------------+--------+------+--------------+ | CSS+CSS3 | X | | +------------+--------+------+--------------+ | HTML+HTML5 | X | | | +------------+--------+------+--------------+ | Photoshop | | X | | +------------+--------+------+--------------+ | Web Dev | X | | | +------------+--------+------+--------------+ | SugarCRM | X | | | +------------+--------+------+--------------+ | Magento | | X | | +------------+--------+------+--------------+ | WordPress | X | | | +------------+--------+------+--------------+ | SEO | X | | | +------------+--------+------+--------------+ | Marketing | X | | | +------------+--------+------+--------------+ |Social Media| X | | | +------------+--------+------+--------------+

Updated on July 28, 2022

Comments

  • JasonDavis
    JasonDavis almost 2 years

    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

  • JasonDavis
    JasonDavis about 7 years
    This is a nice lightweight example of getting colors. Is there a way to limit it to the top used colors. For example the top 8 used colors in an image?
  • CKE
    CKE over 5 years
    Welcome to SO. Thanks for your answer regarding predominant color detection algorithms and for sharing these links. Please note, it's preferred on SO to post the code/algorithm directly instead of sharing it via link.
  • AwesomeGuy
    AwesomeGuy over 5 years
    The current code version in their repository doesn't have class Client nor method loadPng() so you should update your answer with the new code, or for that matter, I will edit your answer with the code I made working.
  • jspit
    jspit over 3 years
    This algorithm does not provide a main color, but the mixed color.
  • fmw42
    fmw42 almost 3 years
    Use PHP exec().
  • Omiod
    Omiod over 2 years
    With this you get just an average of the colors images, usually a gray IMHO