2012-05-11 14 views
5

Ist es möglich zu überprüfen, ob eine bestimmte hexadezimale Farbe näher an FFF oder 000 liegt, basierend auf einem definierten 'Mittelwert'?Farbdifferenz berechnen

Ich möchte überprüfen, ob eine Farbe näher an #FFF oder # 000 basierend auf # 888 liegt. Also, wenn ich nach #FEFEF überprüfen, sollte es #FFF zurückgeben und wenn ich # 878787 versuche, sollte es # 000 zurückgeben.

Wie kann dies erreicht werden? Ich bin nicht sicher, was auf Google suchen ...

Vielen Dank im Voraus

+1

ist nicht # 898989 höher als # 888 (# 888888) und sollte daher #fff zurückgeben? # 878787 sollte der höchste Wert sein, der # 000 meiner Meinung nach zurückgibt ... – oezi

+0

Sie müssen entscheiden, wie der [Abstand] (http://en.wikipedia.org/wiki/Color_difference) berechnet werden soll. – Jon

+1

@oezi: Er möchte # 888 als Bias-Referenzfarbe verwenden, was bedeutet, dass er eine Farbe zwischen # 888 und #FFF vergleichen und entweder # 000 oder #FFF zurückgeben möchte, je nachdem, welcher näher ist (im Prinzip return # 000, wenn die Farbe näher an # 888 als an #FFF ist. –

Antwort

2

Der einfachste Weg, um Ihr Problem zu lösen, ist die Berechnung der Entfernung zwischen Farben mit ihren Graustufen (es gibt andere Möglichkeiten, aber das ist einfach). So etwas wie:

// returns a distance between two colors by comparing each component 
// using average of the RGB components, eg. a grayscale value 
function color_distance($a, $b) 
{ 
    $decA = hexdec(substr($a, 1)); 
    $decB = hexdec(substr($a, 1)); 
    $avgA = (($decA & 0xFF) + (($decA >> 8) & 0xFF) + (($decA >> 16) & 0xFF))/3; 
    $avgB = (($decB & 0xFF) + (($decB >> 8) & 0xFF) + (($decB >> 16) & 0xFF))/3; 
    return abs($avgA - $avgB); 
} 

// I am going to leave the naming of the function to you ;) 
// How this works is that it'll return $minColor if $color is closer to $refColorMin 
// and $maxColor if $color is closer to $refColorMax 
// all colors should be passed in format #RRGGBB 
function foo($color, $refColorMin, $refColorMax, $minColor, $maxColor) 
{ 
    $distMin = color_distance($color, $refColorMin); 
    $distMax = color_distance($color, $refColorMax); 
    return ($distMin < $distMax) ? $minColor : $maxColor; 
} 

// Example usage to answer your original question: 
$colorA = foo('#EFEFEF', '#888888', '#FFFFFF', '#000000', '#FFFFFF'); 
$colorA = foo('#898989', '#888888', '#FFFFFF', '#000000', '#FFFFFF'); 
// Check the values 
var_dump($colorA, $colorB); 

Die Ausgabe lautet:

string(7) "#FFFFFF" 
string(7) "#000000" 
3

Sie die Farben Zahlen umwandeln könnte:

$color_num = hexdec(substr($color, 1)); // skip the initial # 

Dann vergleichen sie entweder 0x0 oder 0xffffff.

Sie könnten sie auch in R, G und B zerlegen und drei Vergleiche anstellen; dann durchschnitt sie? Nicht sicher, wie genau Sie diese Sache wollen :)

+0

Es ist keine gute Idee, die konvertierten Dezimalwerte direkt zu vergleichen, da die für einige Komponenten gespeicherten Bits höhere Werte haben als die Komponenten für andere. So zum Beispiel, wenn die roten Bits in den höchstwertigen Bits gespeichert wurden und blauen Bits in Bits niedrigster Ordnung, gewichten die roten Bits insgesamt mehr als die blauen und grünen Bits würde, was nicht sehr genaue Ergebnisse überhaupt geben würde. Ihre Idee, einen Durchschnittswert zu verwenden, ist gut; Das habe ich auch in meiner Antwort verwendet. –

+0

@reko_t guter Punkt :) Ihre Antwort ist wesentlich mehr ausgearbeitet als meine hehe –

1

Sie so etwas wie das folgende tun könnte:

function hex2rgb($hex) { 
    $hex = str_replace("#", "", $hex); 

    if(strlen($hex) == 3) { 
     $r = hexdec(substr($hex,0,1).substr($hex,0,1)); 
     $g = hexdec(substr($hex,1,1).substr($hex,1,1)); 
     $b = hexdec(substr($hex,2,1).substr($hex,2,1)); 
    } else { 
     $r = hexdec(substr($hex,0,2)); 
     $g = hexdec(substr($hex,2,2)); 
     $b = hexdec(substr($hex,4,2)); 
    } 
    $rgb = array($r, $g, $b); 
    //return implode(",", $rgb); // returns the rgb values separated by commas 
    return $rgb; // returns an array with the rgb values 
} 

$rgb = hex2rgb("#cc0"); 

Von dass Sie die Werte von $ rgb nehmen und sehen, ob ihre Werte im Durchschnitt von mehr als oder weniger als 122,5. Wenn Sie größer als 122,5 sind, sind Sie näher an #FFFFFF, niedriger als 122,5, und Sie wären näher an # 000000.

0

Vielen Dank allen für die Hilfe!

In meinem Startpost habe ich einen kleinen Tippfehler gemacht, wie von oezi erwähnt. Für mich war die Lösung eine kleine Änderung an der akzeptierte Antwort (von reko_t):

function color_distance($sColor1, $sColor2) 
{ 
    $decA = hexdec(substr($sColor1, 1)); 
    $decB = hexdec(substr($sColor2, 1)); 
    $avgA = (($decA & 0xFF) + (($decA >> 8) & 0xFF) + (($decA >> 16) & 0xFF))/3; 
    $avgB = (($decB & 0xFF) + (($decB >> 8) & 0xFF) + (($decB >> 16) & 0xFF))/3; 
    return abs($avgA - $avgB); 
} 

function determine_color($sInputColor, $sRefColor, $sMinColor, $sMaxColor) 
{ 
    $distRef = color_distance($sInputColor, $sRefColor); 
    $distMin = color_distance($sInputColor, $sMinColor); 
    $distMax = color_distance($sInputColor, $sMaxColor); 

    return $distMax - $distRef < $distMin - $distRef ? $sMinColor : $sMaxColor; 
} 

ich diese Funktion benötigt Text-Farbe auf einem Hintergrund-Farbe zu bestimmen, die durch eine Einstellung eingestellt werden kann. Vielen Dank! :) Dank an reko_t!