Première tentative : la couleur d'une image réduite en 1x1 pixel

$filename = "mon_image.jpg"; $img = imagecreatefromjpeg($filename); list($w, $h) = getimagesize($filename); $img2 = imagecreatetruecolor(1, 1); imagecopyresampled($img2, $img, 0, 0, 0, 0, 1, 1, $w, $h); imagedestroy($img); $color = imagecolorat($img2, 0, 0); $result = imagecolorsforindex($img2, $color); imagedestroy($img2);

Ici, $result nous donne donne donc la couleur (en RGB) du seul pixel de notre nouvelle image. La couleur est légèrement différente avec imagecopyresize.

Cela peut nous donner une idée sur plusieurs couleurs (il suffit de redimensionner l'image en 3x3 pour avoir les 9 couleurs "moyennes") mais ici, pour une seule couleur cela nous donne très souvent une couleur grisâtre...

Seconde tentative : la couleur moyenne de toutes les couleurs d'une image

Issue des commentaires de la fonction imagecolorat.

$filename = "mon_image.jpg"; $img = imagecreatefromjpeg($filename); list($w, $h) = getimagesize($filename); $r = $g = $b = 0; for($y = 0; $y < $h; $y++) { for($x = 0; $x < $w; $x++) { $rgb = imagecolorat($img, $x, $y); $r += $rgb >> 16; $g += $rgb >> 8 &255; $b += $rgb &255; } } $pxls = $w * $h; $r = dechex(round($r / $pxls)); $g = dechex(round($g / $pxls)); $b = dechex(round($b / $pxls)); if (strlen($r) < 2) { $r = 0 . $r; } if (strlen($g) < 2) { $g = 0 . $g; } if (strlen($b) < 2) { $b = 0 . $b; } imagedestroy($img); $result = "#" . $r . $g . $b;

Troisième tentative : on pixelise une image

Voir la fonction pixelate de http://www.hudzilla.org/phpbook/read.php/11_2_24. Il faut ensuite prendre la couleur des pixels ainsi créés.
Grosso modo on se retrouve avec les mêmes problèmes que la première tentative.

Image pixelisé du pangolin croustichoquant

Quatrième tentative : on transforme une image en vraies couleurs en image à palette

On transforme en l'image en image à palette et pour chaque index de la palette, on affiche sa couleur.

$filename = "mon_image.jpg"; $nbColor = 9; $img = imagecreatefromjpeg($filename); imagetruecolortopalette($img , true, $nbColor); $cc = imagecolorstotal($img ); for($n = 0; $n < $cc; $n++) { $c = imagecolorsforindex($img , $n); $result[] = sprintf('#%02X%02X%02X', $c['red'], $c['green'], $c['blue']); } imagedestroy($img);

En réduisant les couleurs d'une image à palette de 9 couleurs, on peut se dire que seules les 9 couleurs dominantes restent. Sauf que dans la palette il y a systématiquement du blanc. Curieux. Je n'ai pas vraiment réussi à comprendre pourquoi une couleur blanche était toujours présente.
En plus si on indique 9 couleurs pour l'image à palette, on en a généralement moins. Il faut donc en faire une fonction récursive avec pour "condition stop" le fait que le nombre de couleurs réelles dans la palette correspond au nombre voulu...

Tentative finale : on "arrondi" les couleurs et on compte leur présence

On comptabilise le nombre de pixels présents dans l'image pour chacune des couleurs converti en websafe. Au final, on obtient un tableau représentatif des dominances par couleur.

function colorPalette($imgname) { $im = imagecreatefromjpeg($imgname); $width = imagesx($im); $height = imagesy($im); $palette = array(); for ($j = 0;$j < $height;$j++) { for ($i = 0;$i < $width;$i++) { $color = imagecolorat($im, $i, $j); $r = ($color >> 16) &0xFF; $g = ($color >> 8) &0xFF; $b = $color &0xFF; $rgbtohex = dechex($color); $websafe = hex2websafe($rgbtohex); if (array_key_exists($websafe, $palette)) { $palette[$websafe]++; } else { $palette[$websafe] = 1; } } } arsort($palette); imagedestroy($im); return $palette; } function hex2websafe($hex) { // websafe color : only "00", "33", "66", "99", "CC" or "FF" $step= 51; $result = ""; $rgb['r'] = hexdec(substr($hex, 0, 2)); $rgb['g'] = hexdec(substr($hex, 2, 2)); $rgb['b'] = hexdec(substr($hex, 4, 2)); foreach($rgb as $color) { $websafe = $step * round($color / $step); $result .= str_pad(dechex($websafe), 2, '0', STR_PAD_LEFT); } return $result; } function limitedPalette($palette, $length) { $n = 0; $result = array(); foreach ($palette as $key => $values) { $result[$key] = $values; $n++; if ($n >= $length) break; } return $result; } $filename = "pangolin.jpg"; //On chope toutes les couleurs de l'image $allColors = colorPalette("$filename"); //on prend seulement les 8 premières couleurs $limitedColors = limitedPalette($allColors, 8); //on affiche les 8 couleurs dominantes de l'image echo "<p><img src=".$filename." /></p>"; foreach ($limitedColors as $color => $infos) { echo "<div style='background-color:#$color;width:100px;height:100px;'>#$color</div>"; }

Tout cela nous donne :

Exemple du palettage d'une image, couleurs dominantes

Conclusion

Au terme d'une lutte acharnée avec mon image de pangolin, la palette finale des 8 couleurs représente assez bien les couleurs dominantes de cette image.
Si l'on veut écarter les nuances de couleurs (ici nous avons des bleus relativement proche) il faut allez plus loin qu'un simple "arrondissement" des couleurs en websafe. Pour cela on peut modifier le pas (51 (ou 0x33) pour le websafe, un nombre supérieur pour un "arrondissement" plus prononcé). Attention aux effets de bords cependant...