Подтвердить что ты не робот

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

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

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

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

На рисунке ниже снимок Dribble ниже - это библиотека 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? Возможно, что-то существует уже, что вы знаете или какие-либо советы, чтобы поставить меня на шаг ближе к этому, будет оценено

4b9b3361

Ответ 1

Вот именно то, что вы ищете в 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);

Ответ 2

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

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

Ответ 3

Вам нужно уменьшить масштаб изображения, и вы получите основные цвета изображения. Если вам нужно 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;

}
?>

Прекрасно подходит для меня.

Ответ 4

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

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

Ответ 5

Попробуйте это: 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)

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

Ответ 6

У меня есть сценарий оболочки 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 all означает печать всех подсчетов и цветов для полученных 6 цветов. -s save указывает на сохранение образца изображения.

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

enter image description here

Ответ 7

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

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

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