使用PHP检测图像中的主要颜色

时间:2012-04-24 00:37:44

标签: php image-processing imagemagick gd

我正在尝试复制Dribbble.com检测图像中主要颜色的功能。在下图中,您可以看到Dribbble.com的屏幕截图,其中显示了左侧图像中的8种主要颜色。以下是图片http://dribbble.com/shots/528033-Fresh-Easy?list=following

中的实际页面

我需要能够在PHP中执行此操作,一旦我获得了我需要的颜色,我将它们保存到数据库中,因此不需要在每个页面加载时运行处理。

在对如何从图像中获取这些颜色的一些研究之后,有些人说你只是逐个像素地检查图像,然后保存最多出现的颜色。其他人说它还有更多,并且获得最常见的颜色不会产生预期的效果。他们说你需要量化图像/颜色(此时我迷失了)。

在下面的图片中,下面的Dribble镜头是一个Javascript库,可以执行相同的操作,可以在此处查看该页面http://lokeshdhakar.com/projects/color-thief/

查看该页面的来源我可以看到有一个名为quantize.js的Javascript文件,结果非常好。所以我希望能够使用PHP和GD / ImageMagick来完成Javascript库的功能

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 个答案:

答案 0 :(得分:33)

以下是您在PHP中寻找的内容:https://github.com/thephpleague/color-extractor

示例:

use League\ColorExtractor\ColorExtractor;
use League\ColorExtractor\Palette;

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

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

答案 1 :(得分:12)

这是获取图像主色的简单方法

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

?>

答案 2 :(得分:6)

您需要缩小图片,然后才能获得图片的主要颜色。如果托盘中需要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;

}
?>

适合我的作品。

答案 3 :(得分:3)

您链接到的页面上有一个指向GitHub源代码的链接,所以如果您想知道它们的确切方式,您可以用PHP复制它们的源代码。

他们如何做以及如何做到这一点的最大区别在于他们正在使用群集来查找颜色。它们存储时不是将颜色四舍五入,而是将所有原始颜色存储在一个数组中。然后,它们遍历此数组,直到找到群集中点数与群集中颜色数量最高的群集。这个中心点是最常见的颜色。然后,调色板由下一组最高的聚类定义,其中一些逻辑可防止聚类几乎完全重叠。

答案 4 :(得分:1)

试试这个:http://www.coolphptools.com/color_extract

适用于JPEG和PNG。

最好的!:没有作曲家的喧嚣,只需要require_once

function bar(){
    var baz = {};
    baz.a = 42;
    baz.foo = foo;
    baz.foo();
}

给你这样的东西:

  

阵列(       [3060a8] =&gt; 0.55827380952381       [f0a848] =&gt; 0.19791666666667       [000000] =&gt; 0.069642857142857       [483018] =&gt; 0.02047619047619       [786018] =&gt; 0.01827380952381       [183060] =&gt; 0.01797619047619       [4878a8] =&gt; 0.016011904761905       [181800] =&gt; 0.015119047619048       [a87830] =&gt; 0.014345238095238       [a8c0d8] =&gt; 0.011904761904762       [6090c0] =&gt; 0.01172619047619       [d89030] =&gt; 0.011011904761905       [90a8d8] =&gt; 0.0071428571428571       [ffffff] =&gt; 0.0070238095238095       [604830] =&gt; 0.006547619047619       [f0f0f0] =&gt; 0.0063095238095238       [d8d8f0] =&gt; 0.005297619047619       [c0d8d8] =&gt; 0.0044047619047619       [f0f0ff] =&gt; 0.00041666666666667       [181830] =&gt; 0.00011904761904762)

我尝试了不同的图像,看起来很可靠。

答案 5 :(得分:1)

我有一个使用ImageMagick的Unix bash shell脚本,称为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 all表示为结果6种颜色打印所有计数和颜色。 -s save指示保存样本图像。

根据上面的列表,下面的颜色显示为主色在左侧,而计数颜色则向右递减。

enter image description here

答案 6 :(得分:0)

获取图像主要颜色的想法有些棘手,因为例如,最频繁出现的像素颜色可能在图像中分散得如此之广,以至于根本不会被认为是主要颜色。

我认为像Color coherence vector这样的算法将足以克服该问题,因为它将颜色分为相干和不相干(这很直观),然后您可以使用它们来丢弃那些假阳性。颜色。

我认为这是一种易于实现的算法,本教程Image Retrieval: Color Coherence Vector describes通过示例说明其工作原理,甚至在其末尾提到了matlab实现。