Comparer couleurs / trouver les couleurs proches

Petit nouveau ! | 2 Messages

23 févr. 2009, 14:04

Hello,

Après de longue recherche sur Internet, je n'arrive pas à trouver de réponse à la problèmatique suivante :

Je recherche une fonction qui pourrait me dire si oui ou non une couleur est proche d'une autre.

Exemple :
j'ai plusieurs nuances de rouges : #ff3333, #ff6666, #cc0000, #cc3333
et j'aimerais que la fonction, quand je le compare au rouge basique #FF0000 me renvoi VRAI si c'est du rouge, False si il ne s'agit pas d'une nuance de couleur proche (par exemple si je compare avec une nuance de jaune).

C'est évident pour un humain, mais j'avoue ne pas avoir trouvé la logique en php qui me permettrait de faire cette comparaison.

Avez vous des pistes de recherche à me soumettre ? j'ai regarder du coté des fonctions img de php, j'ai aussi essayé de transformer en décimal, mais aucune logique n'apparait.

Cordialement,
Pistolero

ViPHP
ViPHP | 4039 Messages

23 févr. 2009, 14:14

ben tu décomposes, et tu compares.

Un nuance de rouge aura une plus grande valeur que les deux autres (réunies ?). Et plus sa valeur et la différence d'avec le bleu et le vert seront élevés, plus elle sera saturée.
Mais qu'importe. (je suis ici - dernier petit projet)
Berze going social.

Petit nouveau ! | 2 Messages

23 févr. 2009, 14:37

Quand tu parles de décomposer je pense que tu parle de transformer en couleur RGB.

J'utilise cette fonction :
function html2rgb($color)
{
  // gestion du #...
  if (substr($color,0,1)=="#") $color=substr($color,1,6);

  $tablo[0] = hexdec(substr($color, 0, 2));
  $tablo[1] = hexdec(substr($color, 2, 2));
  $tablo[2] = hexdec(substr($color, 4, 2));
  return $tablo;
}
Ce qui me donne pour les couleurs suivantes :

Couleur 000000 Noir RGB : 0 0 0
Couleur FFFFFF Blanc RGB : 255 255 255
Couleur FBFDE3 Blanc ivoire RGB : 251 253 227
Couleur 7D7D7D Gris RGB : 125 125 125
Couleur 990000 Bordeaux RGB : 153 0 0
Couleur 33CC00 Vert RGB : 51 204 0
Couleur FFFF66 Jaune RGB : 255 255 102
Couleur FFCC00 Orange RGB : 255 204 0
Couleur FF0000 Rouge RGB : 255 0 0
Couleur FF33FF Rose RGB : 255 51 255
Couleur 0000FF Bleu RGB : 0 0 255
Couleur 9933FF Violet RGB : 153 51 255
Couleur 996600 Marron RGB : 153 102 0

Effectivement y'a des résultats (un peu délicat pour détecter le orange par exemple), je vais voir ce que je peux bricoler la dessus. Ci d'autre personne ont des fonctions toutefaites, voir des classes je suis preneur aussi.

Merci, j'étais décidement parti trop compliqué.

Pistolero

ViPHP
ViPHP | 4039 Messages

23 févr. 2009, 14:51

Quelque part, c'est déjà en RGB, mais juste exprimé en hexadécimal.

J'essayerais de d'utiliser la différence entre la valeur du canal rouge et les deux autres réunis. Plus la marge est importante, plus la couleur sera proche du rouge.

Ainsi, pour comparer, il ne te restera qu'a fixer un seuil pour décider ce qui est une teinte de rouge et ce qui ne l'est pas.
Mais qu'importe. (je suis ici - dernier petit projet)
Berze going social.

ViPHP
ViPHP | 1996 Messages

23 févr. 2009, 14:57

Bonjour,

A propos de cela : il y a un moyen logique de passer de rgb (255,0,0) à #FF0000.
Si tu prends l'exemple de http://www.commentcamarche.net/contents/base/hexa.php3

Tu peux voir que FF correspond en base 10 à :
Fx16^1 + Fx16^0 =
15x16+15x1 =
240 + 15 =
255 pour le rouge

Dans tes quatre exemples :
#ff3333 - #ff6666 - #cc0000 -#cc3333
seront égales à
255,51,51 - 255,102,102 - 204,0,0 - 204,51,51

Si tu dis que les valeurs vert et blue t'éloigne de ton objectif quand elle sont grandes, tu vois que :
204,0,0 > 255,51,51> 204,51,51> 255,102,102.

Après à toi de créer ton algorithme pour vérifier si ta nuance est près ou éloignée d'un autre nuance. Utilises pour cela une pondération pour chaque couleur avec un système de balance (comme un système de centre de gravité). Pour t'imaginer le système : Tu as un triangle équilatérale à 255 cm de côté en équilibre en son centre. Si tu modifie un des côtes, le centre de gravité va changer vers l'un ou l'autre des angles.
Tu peux aussi imaginer en 3 dimensions avec 3 axes vectoriels.

Le plus simple est, dans ton cas, (à mon avis) d'ajouter les deux autres couleurs :
Pour 255,51,51 versus 204,51,51 :
255 - (51+51) versus 204 - (51+51)
153 versus 102

Dans cet exemple (non confirmé) 102 est plus éloigné de ta cible qui reste 255.

J'espère t'avoir aidé.
Un conseil créé une fonction pour passer de Hexadécimal à base 10. Je peux te filer un coup de main si tu veux.

Edit : vient de voir les autres post... pas assez rapide...
It is nice to be important but it is more important to be nice
http://www.aureuswebfactory.fr

Eléphant du PHP | 185 Messages

23 févr. 2009, 17:54

Si ça tenait que de moi, je transformerai ton RGB en HLS (teinte, saturation et luminosité), tu vérifies que la les 3 valeurs sont dans un bon intervalle ça roule quoi. ;)

Eléphant du PHP | 185 Messages

23 févr. 2009, 19:05

Allez, j'avais du temps à perdre ! ;)
<?php

function html2rgb($color) 
{
	$color = ltrim($color, '#');

	$r = hexdec(substr($color, 0, 2)); 
	$g = hexdec(substr($color, 2, 2)); 
	$b = hexdec(substr($color, 4, 2)); 
	return array($r, $g, $b);
}

function diff360($a, $b)
{
	if ($a > $b) list($a, $b) = array($b, $a);
	$c = $b-$a;
	return ($c < 180) ? $c : 360+($a-$b);
}

function rgb2hls($rgb)
{
	for ($c=0; $c<3; $c++) {
		$rgb[$c] = $rgb[$c] / 255;
	}

	$hls = array(0, 0, 0);
	$max = max($rgb);
	$min = min($rgb);

	$hls[1] = ($max + $min) / 2;
	if ($max == $min) {
		$hls[0] = 0;
		$hls[2] = 0;
	} else {
		$delta = $max - $min;
		$hls[2] = ($hls[1] <= 0.5) ? ($delta / ($max + $min)) : ($delta / (2 - $delta));

		if ($rgb[0] == $max) {
			$hls[0] = ($rgb[1] - $rgb[2]) / $delta;
		} else if ($rgb[1] == $max) {
			$hls[0] = 2 + ($rgb[2] - $rgb[0]) / $delta;
		} else {
			$hls[0] = 4 + ($rgb[0] - $rgb[1]) / $delta;
		}

		$hls[0] *= 60;
		if ($hls[0] < 0) {
			$hls[0] += 360;
		}
		if ($hls[0] > 360) {
			$hls[0] -= 360;
		}
	}
	ksort($hls);
	return $hls;
}

function similar_color($rgb1, $rgb2, $tolerance = 10)
{
	$hls1 = rgb2hls($rgb1);
	$hls2 = rgb2hls($rgb2);
	return (diff360($hls1[0], $hls2[0]) / 1.8) < $tolerance;
}

function test_similar_color($test, $matches)
{
	$span = '<span style="color:%s;">%s</span>';
	$c1 = sprintf($span, $test, $test);
	$rgb = html2rgb($test);
	
	foreach($matches as $color)
	{
		$c2 = sprintf($span, $color, $color);
		echo "$c1 similaire à $c2 ? ".(similar_color($rgb, html2rgb($color)) ? 'Oui !' : 'Non...')."<br />\n";
	}
}

test_similar_color('#ff0000', array('#ff3333', '#ff6666', '#cc0000', '#cc3333'));

ViPHP
ViPHP | 4674 Messages

24 févr. 2009, 17:01

Hey :-),

Une autre façon de voir les choses, tu peux travailler avec les contrastes.
Pour cela, le W3C propose un bel algorithme : Checkpoint 2.2 - Ensure that foreground and background color combinations provide sufficient contrast when viewed by someone having color deficits or when viewed on a black and white screen. Ça peut être une piste intéressante.
« Un handicap est le résultat d'une rencontre entre une déficience ou différence et une incapacité de la société à répondre à celle-ci. »

Hoa : http://hoa-project.net (sur @hoaproject).

Avatar du membre
Administrateur PHPfrance
Administrateur PHPfrance | 9782 Messages

24 févr. 2009, 17:41

Quand tout le reste a échoué, lisez le mode d'emploi...