OVH Cloud OVH Cloud

[GD] greyscale

7 réponses
Avatar
ANTHONY THIBAULT
Bonjour, j'ai ce bout de code qui ne donne rien d'autre que l'image de
départ alors que je voudrais tout simplement rendre l'image en noir et blanc
(et valeurs de gris) :

<?php

$image=imagecreatefromJPEG("00.jpg");

$total = imagecolorstotal($image);
for( $i=0; $i<$total; $i++){
$old = imagecolorsforindex($image, $i);

$commongrey = (int)(($old[red] + $old[green] + $old[blue]) / 3);
imagecolorset($image, $i, $commongrey, $commongrey, $commongrey);
}
imageJPEG($image, '', 100);

?>

Où est-ce que j'ai fait une erreur ?
(dernières version de php et gd installées)

--
________________
Anthony THIBAULT
www.anthony-thibault.com
www.graphismedia.com

7 réponses

Avatar
Nicolas
Trouvé sur google à propos de la fonctions imagecolorstotal() qui renvoie 0
avec gd2.0 :

"24/32 bit color images have too many colors to count. In order to offer
the requested functionality PHP would need to go through every single
pixel of the image analyzing the colors used and creating an array of
stored colors. This is simply way too slow & memory consuming to be
implemented."

Si je comprends bien, pour faire un script qui manipule les couleurs d'une
image (jpeg) avec la gd2.0 (balance des couleurs, luminosité, passage en
noir et blanc etc.), je n'ai pas vraiment d'autre solution que de traiter
les couleurs pixel par pixel ?

Nicolas
Avatar
Nicolas
Où est-ce que j'ai fait une erreur ?
(dernières version de php et gd installées)


Aucune erreur chez moi avec ton code, l'image retournée est bien en noir et
blanc.
PHP 4.2.0
GD 1.6.2

En revanche chez certains de mes hébergeurs, je rencontre le même problème
PHP 4.2.0
GD 2.0 ou 1.8

J'ai l'impression que la fonction imagecolorstotal() renvoie 0 ou false !

Nicolas

Avatar
ANTHONY THIBAULT
"Nicolas" a écrit dans le message de
news:blbv8b$ef6$
Aucune erreur chez moi avec ton code, l'image retournée est bien en noir
et

blanc.
PHP 4.2.0
GD 1.6.2

En revanche chez certains de mes hébergeurs, je rencontre le même problème
PHP 4.2.0
GD 2.0 ou 1.8

J'ai l'impression que la fonction imagecolorstotal() renvoie 0 ou false !


Je crois avoir trouvé et ça ne m'arrange pas ://
en fait il semble que GD 2 ne peut utiliser cette fonction uniquement sur
des images ayant une palette (et pas en truecolor comme le jpeg par
exemple), il faut donc transformer au préalable l'image en image à palette
avant de pouvoir la manipuler.. ce qui rend l'image immonde avant son
traitement ://

dommage, et merci quand même :))
________________
Anthony THIBAULT
www.anthony-thibault.com
www.graphismedia.com

Avatar
Lascap
Alors déjà, du gris ce n'est pas rouge + bleu + vert / 3, ça serait trop
facile. il y a des coeffs a prendre en compte, qui sont les suivants:

$gris = 0.3 * rouge + 0.59 * vert + 0.11 * bleu

et apres, je pense que l'erreur vient de la ligne

$old = imagecolorsforindex($image, $i);

qui devrait plutot etre quelque chose du genre $old imagecolorsforindex($image, imageColorAt($image, $i));

bon, sinon, tu peux regarder de ce coté là, j'ai écrit une fonction qui fait
ça (bon, elle fait partie d'un objet, mais reste assez simple à adapter, je
pense)

function _niveauxGris() {
$this->copie = imageCreate($this->w, $this->h);

for($i=0; $i<$this->w; $i++)
{
for($j=0; $j<$this->h; $j++)
{
$rvb = imagecolorsforindex($this->original,
imageColorAt($this->original, $i, $j));
$niv = intval((0.3 * doubleval($rvb["red"])) + (0.59 *
doubleval($rvb["green"])) + (0.11 * doubleval($rvb["blue"])));
$couleur = imagecolorallocate($this->copie, $niv,$niv,$niv);
imageSetPixel($this->copie, $i, $j, $couleur);
}
}
}

voilà voilà
Lascap
Avatar
Jean-Marc Molina
Bizarre mon message n'est jamais arrivé...
Pour résumer il te faut travailler au niveau des pixels car les images JPEG
n'ont pas de palettes, ce sont des images truecolor (24bits ou plus).
Il te faut donc utiliser colorat et setpixel sur chaque pixel.
Pour chaque composante RGB il te faut calculer une moyenne pour obtenir un
gris, tu peux utiliser la formule R + V + B / 3 qui est approximative car on
ne perçoit pas ces 3 composantes au même niveau.
Je ressors une vieille doc pour compléter les infos de Lascap :

Couleur
RGB vers GREY
Méthode simple : Luminiostié = ( R + G + B ) / 3

L'oeil humain ne perçoit pas le Rouge, le Vert et le Bleu a une même
intensité. Donc il est préférable de pondérer chacune des composantes d'une
couleur pour la convertir en une intensité lumineuse. Nous sommes plus
sensibles au Vert par exemple : Luminiostié = ( 0.299 * R + 0.587 * G +
0.114 * B )

JM

ps : je crois que mon message n'est pas passé car il était en HTML (mise en
page oblige)

--
Clé AntiPourriel : PASUNPOURRIEL (ne pas retirer)
Avatar
Nicolas
Grace à vos posts :

<?php
function greyscale($im) {

$sx = imagesx($im);
$sy = imagesy($im);

for($i=0; $i < $sx; $i++) {
for($j=0; $j < $sy; $j++) {
$rvb = imagecolorsforindex($im, imageColorAt($im, $i, $j));
//$niv = intval((0.299 * doubleval($rvb["red"])) + (0.587 *
doubleval($rvb["green"])) + (0.114 * doubleval($rvb["blue"])));
$niv = intval((doubleval($rvb["red"]) + doubleval($rvb["green"]) +
doubleval($rvb["blue"]))/3);
$couleur = imagecolorallocate($im, $niv, $niv, $niv);
imageSetPixel($im, $i, $j, $couleur);
}
}
return $im;
}


// exemple d'utilisation
$im = imagecreatefromjpeg("01.jpg");
$im = greyscale($im);
imagejpeg($im, '', 100);

?>

Nicolas
Avatar
Jean-Marc Molina
Ravi de voir que ça fonctionne :)

Par contre tu dois normalement parcourir ton image de gauche à droite et de
haut en bas. Non pas de haut en bas et de gauche à droite. Il faut respecter
la logique physique de représentation d'une image, et de son affichage. Tu
as donc inversé i et j, i devrait parcourir les y et j les x. Pour ne pas te
tromper (si tu n'es pas super matheux :p), remplace i par y et j par x :
for($y=0; $y < $sy; $y++) {
for($x=0; $x < $sx; $x++) {

$rvb = imagecolorsforindex($im, imageColorAt($im, $i, $j));


C'est très lourd :). Dommage qu'on ne puisse pas récupérer le RVB
directement. C'est historique, la GD ne supportait pas les images truecolors
:(...

$niv = intval((doubleval($rvb["red"]) + doubleval($rvb["green"]) +
doubleval($rvb["blue"]))/3);


Pas besoin de convertir toutes tes valeurs en double, tu peux te compter de
faire une somme et de convertir cette valeur en double ou float (double
c'est bien trop précis à mon avis et beaucoup plus lent, surtout pour des
MILLIERS de pixels) :
$somme = $rvb ['red'] + $rvb ['green'] + $rvb ['blue'];
$niv = intval (floatval ($somme) / 3);

JM

--
Clé AntiPourriel : PASUNPOURRIEL (ne pas retirer)