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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10290259/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 21:50:13  来源:igfitidea点击:

Detect main colors in an image with PHP

phpimage-processingimagemagickgd

提问by JasonDavis

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

我正在尝试复制 Dribbble.com 在检测图像中的主要颜色方面所做的功能。在下图中,您可以看到来自 Dribbble.com 的屏幕截图,其中显示了左侧图像中的 8 种主要颜色。这是图片中的实际页面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.

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

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/

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

Viewing the source of that page I can see there is a Javascript file named quantize.jsand 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

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

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

我发现这个函数会用 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)");
}

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

所以我问是否有人知道我如何用 PHP 完成这样的任务?可能已经存在一些你知道的东西或者任何让我更接近这样做的提示将不胜感激

回答by Epoc

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

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

Example :

例子 :

use League\ColorExtractor\Palette;

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

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

回答by Emanuel Cuccato

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;

回答by Dust999

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 12x8and so on...

您需要缩小图片,您将获得图片的主要颜色。如果您在托盘中需要 4 种颜色,请将其缩小到大约8x86 种颜色到大约 12x8等等...

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

imagecopyresized对于按比例缩小的图像,然后检查每个像素并将它们存储在数组中 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.

非常适合我。

回答by Alex N.

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.

您链接到的页面有一个指向 GitHub 上源代码的链接,因此如果您想确切地知道他们是如何做的,您可以在 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.

他们如何做与您如何做的最大区别在于他们使用聚类来查找颜色。他们在存储颜色时没有对颜色进行四舍五入,而是将所有原始颜色存储在一个数组中。然后他们循环遍历这个数组,直到找到一个簇中的点与簇中颜色数的比率最高的簇。它的中心点是最常见的颜色。然后,调色板由下一个最高的集群集定义,并使用一些逻辑来防止集群几乎完全重叠。

回答by fmw42

I have a Unix bash shell script with ImageMagick called dominantcolor that may do what you want. See my scripts web site at http://www.fmwconcepts.com/imagemagick/index.php. You an run it from PHP exec(). See my pointers for use on my home page.

我有一个带有 ImageMagick 的 Unix bash shell 脚本,称为dominantcolor,它可以做你想做的事。请参阅我的脚本网站http://www.fmwconcepts.com/imagemagick/index.php。您可以从 PHP exec() 运行它。请参阅我的主页上使用的指针。

Input:

输入:

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



The -n 6 is the desired number of colors in the color quantization. The -p all means print all counts and colors for the resulting 6 colors. The -s save indictates to save a swatch image.

-n 6 是颜色量化中所需的颜色数。-p all 表示打印生成的 6 种颜色的所有计数和颜色。-s save 指示保存样本图像。

Colors below are shown with the dominant color on the left and decreasing count colors towards the right according to the list above.

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

enter image description here

在此处输入图片说明

回答by Juergen

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

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

Works with JPEG and PNG.

适用于 JPEG 和 PNG。

And best!: no hustle with composer, just require_once

最好的!:没有与作曲家的喧嚣,只需要 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 )

阵列([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] => 9) 0.047612

I tried it with different images and it seems reliable.

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

回答by v.tmab

The idea of getting the predominant colors of the image is a bit tricky, because for example the most frequent pixel color could be so widely scattered in the image that it is not perceived as a predominant color at all.

获取图像的主要颜色的想法有点棘手,因为例如,最常见的像素颜色可能会在图像中如此广泛地分散,以至于根本不会将其视为主要颜色。

I think an algorithm like Color coherence vectorwill be good enough to overcome this issue, because it clusters the colors into coherent and incoherent (which is quite intuitive), and then you can use them to discard those false positive predominant colors.

我认为像Color coherence vector这样的算法足以解决这个问题,因为它将颜色聚类为相干和不相干(这非常直观),然后您可以使用它们来丢弃那些假阳性的主要颜色。

I see it is an easy algorithm to implement, this tutorial Image Retrieval: Color Coherence Vector describesdescribes its steps with examples of how it works and there is even a matlabimplementation mentioned at the end of it.

我认为这是一种易于实现的算法,本教程Image Retrieval: Color Coherence Vector 描述了它的步骤,并通过示例说明了它的工作原理,甚至在结尾处提到了一个matlab实现。