Convertir image avec palette de couleur donnée

Eléphanteau du PHP | 11 Messages

07 févr. 2006, 14:35

Bonjour,

Je souaiterais convertir une image en restreignant sa palette de couleurs à une palette de couleurs que j'ai definit.

Par exemple : j'ai une image en couleur vraie et je veux qu'elle soit recalculée en utilisant les couleur bleu vert et rouge.
Pour chaque pixel cette fonction chercherait ainsi si la couleur du pixel est plus proche du rouge, du bleu ou du vert !

C'est en fait la meme chose que de convertir une image en 256 couleurs (cas du gif par exemple) sauf que c'est moi qui donne les couleurs !

Je pense a un algo mais je ne sais pas s'il est possible de calculer la distance entre une couleur et une autre ? (en code hexa par exemple)

Merci beaucoup pour cette aide precieuse qui va me servir a calculer la couleur dominante d'une image de maniere fiable.

Administrateur PHPfrance
Administrateur PHPfrance | 11457 Messages

07 févr. 2006, 15:47

Mathématiquement parlant, je pense qu'il te faut concevoir un algorithme
qui attribue la valeur standard pour chacune des composantes R, V et B.

Supposons que pour chacune de ces 3 composantes, tu aies 6 valeurs : 00, 33, 66, 99, CC et FF
ce qui te permet de définir ta palette de couleurs "standard" : 33CC00, FF6699, etc.

Ton algorithme récupère la couleur proposée : E42F88, par exemple
et en isole les 3 composantes : E4, puis 2F, puis 88

Il les compare individuellement aux valeurs standard : 00, 33, 66, ...
et les remplace par la valeur standard la plus proche.

E4 est plus proche de CC que de FF
2F est plus proche de 33 que de 00
88 est plus proche de 99 que de 66
E42F88 :arrow: CC3399

Eléphanteau du PHP | 11 Messages

07 févr. 2006, 18:27

Merci pour ta réponse.

Toutefois je ne suis pas sur que le rendu de cette méthode soit vraiment fiable. Je pense notamment au gris ou R = V = B ou par exemple #555555 devrait être très proche de #DDDDDD.

Enfin, peut être que je me trompe...

Administrateur PHPfrance
Administrateur PHPfrance | 11457 Messages

07 févr. 2006, 18:36

#555555 devrait être très proche de #DDDDDD
:shock:

Selon l'exemple que je t'ai donné, #555555 :arrow: #666666
Ça reste un gris, à peine plus clair.

Eléphanteau du PHP | 11 Messages

07 févr. 2006, 19:00

Oui bien sur que celui la marche car 55 est très proche de 66.
Mais le probleme est de savoir si l'algo marche pour 55 et DD qui eux sont relativement éloignés alors que DDDDDD reste du gris !

De toutes facons j'ai une idée dans la tete pour calculer la distance entre deux couleurs !
Je vais d'ailleurs m'inspirer du fameux algo de math intégré a levenstein qui sert a calculer la distance entre deux mots !
J'espere avoir des resultats convainquants !

Je posterais l'algo par la suite si les résultats sont fiables !

Encore merci pour votre aide !

Invité
Invité n'ayant pas de compte PHPfrance

08 févr. 2006, 18:53

Bonjour,

Voici ma methode complete pour ceux que ca interessent.

Elle realise le calcul de couleur dominante a partir d'un palette, dit si l'image est en couleur, noir et blanc ou niveaux de gris.

Désolé je n'est pas encore eu trop le temps de la commenté ni vraiment de la tester !
private function setCouleurs()
{
$netb = true;
$niveaugris = true;
$palette = Array([0]=>Array(0,0,0), //noir
[1]=>Array(128,128,128), //gris
[2]=>Array(128,0,0), //marron
[3]=>Array(255,0,0), //rouge
[4]=>Array(0,128,0), //vertfoncé
[5]=>Array(0,255,0), //vert
[6]=>Array(128,128,0), //olive
[7]=>Array(255,255,0), //jaune
[8]=>Array(0,0,128), //marine
[9]=>Array(0,0,255), //bleu
[10]=>Array(128,0,128), //violet
[11]=>Array(255,0,255), //fuchsia
[12]=>Array(0,128,128), //cobalt
[13]=>Array(0,255,255), //aqua
[14]=>Array(192,192,192),//argent
[15]=>Array(255,255,255),//blanc
[16]=>Array(255,128,0) //orange
);


for ($i=1 ; $i < ImageSX($this->miniatureNonReechantillonnee) ; $i++) {
for ($j=1 ; $j < ImageSX($this->miniatureNonReechantillonnee) ; $j++) {

$pixel = ImageColorAt($miniatureNonReechantillonnee,$i,$j);

if ($pixel != 0 || $pixel != 255255255) $netb = false;

$r = ($pixel >> 16) & 0xFF;
$v = ($pixel >> 8) & 0xFF;
$b = $pixel & 0xFF;

if ($r != $v || $v != $b || $r != $b) $niveaugris = false;
$distMin = 1000;
for ($k=0 ; $k < count($palette) && $disMin != 0 ; $k++) {
$distance = pow($palette[$k][0] - $r,2) + pow($palette[$k][1] - $v,2) + pow($palette[$k][2] - $b,2);
if ($distance < $distMin){$disMin = $distance;$indCoulProche = $k;}
}
$paletteDom[$indCoulProche]++;
}
}

$max = 0;
foreach ($paletteDom as $key => $val)if ($val > $max)$this->couleurDominante = $key);
$this->couleurDominante = $this->couleurDominante[0].$this->couleurDominante[1].$this->couleurDominante[2];

if ($netb)$this->coloration = 1;
else if ($niveaugris)$this->coloration = 2;
else $this->coloration = 3;
}

Eléphanteau du PHP | 11 Messages

08 févr. 2006, 18:57

Oups désolé je ne m'était pas connecté !
Dommage je ne peux plus rééditer maintenant !

Administrateur PHPfrance
Administrateur PHPfrance | 11457 Messages

08 févr. 2006, 20:31

Pas grave. Tu seras fouetté... :twisted:

Eléphanteau du PHP | 11 Messages

11 févr. 2006, 18:32

Bonjour,

Voici la version finale de mon algo, revue et corrigée :
	private function setCouleurs(){
		$netb = true;
		$niveauxGris = true;
		$palette = Array(Array(0,0,0),	//noir
					Array(128,128,128),  //gris
					Array(128,0,0),		//marron
					Array(255,0,0),		//rouge
					Array(0,128,0),		//vert fonce
					Array(0,255,0),		//vert
					Array(128,128,0),     //olive
					Array(255,255,0),     //jaune
					Array(0,0,128),		//marine
					Array(0,0,255),		//bleu
					Array(128,0,128),     //violet
					Array(255,0,255),     //fuchsia
					Array(0,128,128),     //cobalt
					Array(0,255,255),     //aqua
					Array(192,192,192), //argent
					Array(255,255,255), //blanc
					Array(255,128,0)     //orange
		);
		//palette pondérée et initialisée à 0
		$paletteDom = Array(17);
		for ($i = 0 ; $i < 17 ; $i++)$paletteDom[$i]=0;

		$xMini = (int)ImageSX($this->miniature);
		$yMini = (int)ImageSY($this->miniature);
		// on parcours chaque pixel de la miniature pour regarder sa couleur 
		for ($i=0 ; $i < $xMini; $i++) {
			for ($j=0 ; $j < $yMini ; $j++) {
				$pixel = ImageColorAt($this->miniature,$i,$j);
				if ($pixel != 0 || $pixel != 16777215) $netb = false;
				$r = ($pixel >> 16) & 0xFF;
				$v = ($pixel >> 8) & 0xFF;
				$b = $pixel & 0xFF;
				if ($r != $v || $v != $b || $r != $b) $niveauxGris = false;

				$distMin = 1000000000; $indCoulProche = 0;
				//on determine quelle couleur de la palette est la plus proche de celle du pixel
				//en evaluant leur distance
				for ($k=0 ; $k < count($palette) && $distMin != 0 ; $k++) {
					$distance = pow($palette[$k][0] - $r,2) + pow($palette[$k][1] - $v,2) + pow($palette[$k][2] - $b,2);
					if ($distance < $distMin){
						$distMin = $distance;
						$indCoulProche = $k;
					}
				}
				//on incremente la pondération de a couleur la plus proche
				$paletteDom[$indCoulProche]++;
			}
		}
		print_r($paletteDom);
		$max = 0;
		foreach ($paletteDom as $key => $val)if ($val > $max){$max = $val;$indDom = $key;}
		$this->couleurDominante = hexdec(dechex($palette[$indDom][0]).dechex($palette[$indDom][1]).dechex($palette[$indDom][2]));

		if ($netb)$this->coloration = 1;			//noir et blanc
		else if ($niveauxGris)$this->coloration = 2;//niveaux de gris
		else $this->coloration = 3;					//couleur
	}

ndkdesign
Invité n'ayant pas de compte PHPfrance

14 mars 2012, 15:51

Salut, je viens de tomber sur cette fonction qui semble tout à fait répondre à mon besoin : Modifier les couleurs d'une image avec une palette définie.
Etant novice en php, pourrais tu me dire comment utiliser cette fonction, pour que lui envoyant mon image source, elle me retourne l'image modifiée?

Merci beaucoup.