2010-08-12 14 views
42

Tengo una imagen jpg.Detecta el "promedio general" de color de la imagen

Necesito saber el "promedio general" del color de la imagen. A primera vista, puede usar el histograma de la imagen (canal RGB).

En el trabajo utilizo principalmente JavaScript y PHP (un poco de Python) por lo tanto, recibí con agrado la decisión en estos idiomas. Tal vez hay una biblioteca para trabajar con imágenes que abordan problemas similares.

No necesito determinar dinámicamente el color de la imagen. Necesito pasar una vez por todo el conjunto de imágenes y determinar el color de cada una por separado (esta información la recordaré para uso futuro).

+1

JS no puede acceder a la información de color de una imagen binaria – mplungjan

+0

@mplungjan, existe una biblioteca javascript 'http: // www.pixastic.com/lib/docs /', de alguna manera obtienen información sobre los colores. o estoy equivocado? – Kalinin

+1

Utilizan el nuevo elemento 'Canvas'. –

Respuesta

66

Puede utilizar PHP para obtener una matriz de la paleta de colores de esta manera:

<?php 
function colorPalette($imageFile, $numColors, $granularity = 5) 
{ 
    $granularity = max(1, abs((int)$granularity)); 
    $colors = array(); 
    $size = @getimagesize($imageFile); 
    if($size === false) 
    { 
     user_error("Unable to get image size data"); 
     return false; 
    } 
    $img = @imagecreatefromjpeg($imageFile); 
    // Andres mentioned in the comments the above line only loads jpegs, 
    // and suggests that to load any file type you can use this: 
    // $img = @imagecreatefromstring(file_get_contents($imageFile)); 

    if(!$img) 
    { 
     user_error("Unable to open image file"); 
     return false; 
    } 
    for($x = 0; $x < $size[0]; $x += $granularity) 
    { 
     for($y = 0; $y < $size[1]; $y += $granularity) 
     { 
     $thisColor = imagecolorat($img, $x, $y); 
     $rgb = imagecolorsforindex($img, $thisColor); 
     $red = round(round(($rgb['red']/0x33)) * 0x33); 
     $green = round(round(($rgb['green']/0x33)) * 0x33); 
     $blue = round(round(($rgb['blue']/0x33)) * 0x33); 
     $thisRGB = sprintf('%02X%02X%02X', $red, $green, $blue); 
     if(array_key_exists($thisRGB, $colors)) 
     { 
      $colors[$thisRGB]++; 
     } 
     else 
     { 
      $colors[$thisRGB] = 1; 
     } 
     } 
    } 
    arsort($colors); 
    return array_slice(array_keys($colors), 0, $numColors); 
} 
// sample usage: 
$palette = colorPalette('rmnp8.jpg', 10, 4); 
echo "<table>\n"; 
foreach($palette as $color) 
{ 
    echo "<tr><td style='background-color:#$color;width:2em;'>&nbsp;</td><td>#$color</td></tr>\n"; 
} 
echo "</table>\n"; 

que le da una matriz cuyos valores son superiores a la frecuencia se ha utilizado ese color.

EDITAR Un comentarista preguntó cómo utilizar esto en todos los archivos en un directorio, aquí está:

if ($handle = opendir('./path/to/images')) { 

     while (false !== ($file = readdir($handle))) { 
      $palette = colorPalette($file, 10, 4); 
      echo "<table>\n"; 
      foreach($palette as $color) { 
       echo "<tr><td style='background-color:#$color;width:2em;'>&nbsp;</td><td>#$color</td></tr>\n"; 
      } 
      echo "</table>\n"; 
     } 
     closedir($handle); 
    } 

posible que no quieren hacer esto en demasiados archivos, pero es su servidor.

Alternativamente si prefiere usar JavascriptLokesh's Color-Theif biblioteca hace exactamente lo que está buscando.

+1

¡Hazlo Bang! Cambia '$ img = @imagecreatefromgif ($ imageFile);' a '$ img = @imagecreatefromstring (file_get_contents ($ imageFile));' y ahora puedes procesar diferentes tipos de imágenes ... – Andres

+0

el código para cambiar es en realidad '@imagecreatefromjpeg ($ imageFile); 'actualmente asume que estás usando jpgs. – JKirchartz

+0

¡Uy! Gracias @JKirchartz por atrapar mi locura. ¡Un gran código por cierto! – Andres

2

Una solución más corto imagen de color verdadero para sería modificar la escala a un tamaño de 1x1 píxeles y muestra el color en ese píxel:

$ escalado = imagescale ($ img, 1, 1, IMG_BICUBIC); $ meanColor = imagecolorat ($ img, 0, 0);

... pero no lo he probado yo mismo.

+0

interesante, pero debe ser probado. – Kalinin

+0

@Kalinin se ha probado, consulte [aquí] (http://stackoverflow.com/a/1746564/3075942). – user

+0

nota, esto requiere que PHP se compile con la biblioteca de GD –

4

Combinando JKirchartz y Alexander Hugestrand respuesta:

function getAverage($sourceURL){ 

    $image = imagecreatefromjpeg($sourceURL); 
    $scaled = imagescale($image, 1, 1, IMG_BICUBIC); 
    $index = imagecolorat($scaled, 0, 0); 
    $rgb = imagecolorsforindex($scaled, $index); 
    $red = round(round(($rgb['red']/0x33)) * 0x33); 
    $green = round(round(($rgb['green']/0x33)) * 0x33); 
    $blue = round(round(($rgb['blue']/0x33)) * 0x33); 
    return sprintf('#%02X%02X%02X', $red, $green, $blue); 
} 

de probada eficacia, regresa cadena hexadecimal.

+0

¿Por qué redondearlo? En mi experiencia, no redondearlo proporciona un resultado más preciso, simplemente '' 'return sprintf ('#% 02X% 02X% 02X', $ rgb ['rojo'], $ rgb ['verde'], $ rgb [' blue ']); '' ' – Kevin

+0

@Kevin tendrá que probarlo, gracias por el aviso. –

+0

Esto no siempre funciona para mí – Pons

0

He creado el paquete de compositor que proporciona la biblioteca para elegir un color promedio de la imagen dada por su ruta.

Puede instalarlo ejecutando el siguiente comando en el directorio del proyecto: ejemplo

composer require tooleks/php-avg-color-picker 

Uso:

<?php 

use Tooleks\Php\AvgColorPicker\Gd\AvgColorPicker; 

$imageAvgHexColor = (new AvgColorPicker)->getImageAvgHexByPath('/absolute/path/to/the/image.(jpg|jpeg|png|gif)'); 

// The `$imageAvgHexColor` variable contains the average color of the given image in HEX format (#fffff). 

Véase el documentation.

1
$img = glob('img/*'); 
foreach ($img as $key => $value) { 
    $info = getimagesize($value); 
    $mime = $info['mime']; 
    switch ($mime) { 
     case 'image/jpeg': 
      $image_create_func = 'imagecreatefromjpeg'; 
      break; 
     case 'image/png': 
      $image_create_func = 'imagecreatefrompng'; 
      break; 
     case 'image/gif': 
      $image_create_func = 'imagecreatefromgif'; 
      break; 
    } 
    $avg = $image_create_func($value); 
    list($width, $height) = getimagesize($value); 
    $tmp = imagecreatetruecolor(1, 1); 
    imagecopyresampled($tmp, $avg, 0, 0, 0, 0, 1, 1, $width, $height); 
    $rgb = imagecolorat($tmp, 0, 0); 
    $r = ($rgb >> 16) & 0xFF; 
    $g = ($rgb >> 8) & 0xFF; 
    $b = $rgb & 0xFF; 
    echo '<div style="text-align:center; vertical-align: top; display:inline-block; width:100px; height:150px; margin:5px; padding:5px; background-color:rgb('.$r.','.$g.','.$b.');">'; 
    echo '<img style="width:auto; max-height:100%; max-width: 100%; vertical-align:middle; height:auto; margin-bottom:5px;" src="'.$value.'">'; 
    echo '</div>'; 

se puede obtener el valor de la media de color con r $, $ g, $ b & volver a muestrear la imagen es mucho más mejor que sólo se reduce la escala!

Cuestiones relacionadas