2009-10-27 16 views
12

Szukam funkcji, która może dokładnie odwzorować odległość między dwoma kolorami jako liczbę lub coś."Odległość" między kolorami w PHP

Na przykład szukam mieć tablicę wartości HEX lub tablic RGB i chcę, aby znaleźć najbardziej podobny kolor w tablicy dla danego koloru

np. Przekazuję funkcję o wartości RGB i zwracam "najbliższy" kolor w tablicy

+0

Podobne pytanie: http://stackoverflow.com/questions/1313/followup-finding-an-accurate-distance-between-colors – Kai

Odpowiedz

19

Każdy kolor jest reprezentowany jako krotka w kodzie HEX. Aby ustalić ścisłe dopasowania, musisz odjąć każdy komponent RGB osobno.

Przykład:

Color 1: #112233 
Color 2: #122334 
Color 3: #000000 

Difference between color1 and color2: R=1, G=1 B=1 = 0x3 
Difference between color3 and color1: R=11, G=22, B=33 = 0x66 

So color 1 and color 2 are closer than 
1 and 3. 

edit

Więc chcesz najbliższy nazwie kolor? Utwórz tablicę z wartościami heksadecymalnymi każdego koloru, wykonaj iterację i zwróć nazwę. Coś takiego;

function getColor($rgb) 
{ 
    // these are not the actual rgb values 
    $colors = array(BLUE =>0xFFEEBB, RED => 0x103ABD, GREEN => 0x123456); 

    $largestDiff = 0; 
    $closestColor = ""; 
    foreach ($colors as $name => $rgbColor) 
    { 
     if (colorDiff($rgbColor,$rgb) > $largestDiff) 
     { 
      $largestDiff = colorDiff($rgbColor,$rgb); 
      $closestColor = $name; 
     } 

    } 
    return $closestColor; 

} 

function colorDiff($rgb1,$rgb2) 
{ 
    // do the math on each tuple 
    // could use bitwise operates more efficiently but just do strings for now. 
    $red1 = hexdec(substr($rgb1,0,2)); 
    $green1 = hexdec(substr($rgb1,2,2)); 
    $blue1 = hexdec(substr($rgb1,4,2)); 

    $red2 = hexdec(substr($rgb2,0,2)); 
    $green2 = hexdec(substr($rgb2,2,2)); 
    $blue2 = hexdec(substr($rgb2,4,2)); 

    return abs($red1 - $red2) + abs($green1 - $green2) + abs($blue1 - $blue2) ; 

} 
+0

Rozumiem, że muszę uzyskać wartości RGB, ale szukam funkcji, która dla może zwrócić "najbardziej podobny" kolor w tablicy dla danego koloru. Prosty przykład: [niebieski, czerwony, darkred GREEN] Jeśli funkcja podano kolor jasnoniebieski, z tablicy powyżej Id oczekiwać, że funkcja zwraca „niebieski” Na zdrowie Philip – Phil

+0

Jeśli w ogóle nie wzywamy wartości szesnastkowej, po prostu utwórz funkcję z dużą instrukcją switch, która przyjmuje nazwę koloru i po prostu zwraca to, co uważasz za najbliższą nazwę koloru. –

+3

Funkcja colofDiff jest dobra, ale musi naprawić błąd w zamian: "return abs ($ red1 - $ red2) + abs ($ green1 - $ green2) + abs ($ blue1 - $ blue2);" – Cesar

4

Bardzo prostym podejściem jest obliczenie sumarycznej odległości między trzema wymiarami. Na przykład simple_distance ("12,10255", "10,10,250") = 7

Bardziej wyrafinowanym podejściem byłoby zajęcie kwadratu odległości dla każdego komponentu i zsumowanie tych - w ten sposób elementy będą zbyt daleko "ukarany" więcej: square_distance ("12,10255", "10,10,250") = 2 * 2 + 0 * 0 + 5 * 5 = 29.

Oczywiście trzeba będzie powtórzyć listę kolorów i znaleźć najbliższą.

1

możesz przekonwertować swoją wartość RGB na HSL lub HSV. wtedy kolory są łatwe do porównania: najpierw uporządkuj kolory według odcienia, potem nasycenia, potem luminancji. w wynikowej kolejności 2 kolory obok siebie będą wyglądać bardzo blisko percepcyjnie.

uwaga, że ​​odcień się otacza: dla odcienia od 0 do 255, odcień 0 i odcień 255 są bardzo bliskie.

patrz artykuł na HSL http://en.wikipedia.org/wiki/HSL_and_HSV dla wzoru, który pozwoli na konwersję RGB do HSL

(należy pamiętać, że inne przestrzenie kolorów, jak laboratorium, może dać lepsze rezultaty, ale konwersja jest bardziej skomplikowane)

zdefiniujmy to matematycznie:

distance(A(h,s,l), B(h,s,l)) = (A(h)-B(h)) * F^2 + (A(s)-B(s)) * F + (A(l)-B(l)) 

gdzie F jest współczynnikiem starannie dobrane (coś jak 256 ...)

Powyższy wzór nie uwzględnia odbarwiania barwy ...

+0

to nie ma sensu. Jeśli kolory A i B miały niewielką różnicę luminancji i tego samego odcienia, a kolory A i C miały taką samą jaskrawość i dużą różnicę barwy (powiedzmy, że jest czerwona, a druga jest zielona ...), odległość między A a B będzie większe niż odległość między A i C ... –

+0

Wygląda na to, że źle zrozumiałeś porządek, który proponuję: najpierw zamawiasz według odcienia, następnie zamawiasz kolory o tym samym odcieniu przez nasycenie, na końcu zamawiasz kolory o jednakowym odcieniu i nasyceniu luminancją. biorąc pod uwagę tę kolejność, kolory A i B mają ten sam odcień, a odległość (A, B) jest mniejsza niż (A, C). –

+0

Edytowałem swoją odpowiedź, aby dołączyć małą formułę matematyczną, która, mam nadzieję, pomaga lepiej zrozumieć porządek ... –

12

Here is a paper on the subject, która powinna dać dobrą odpowiedź.

Myślałem, że konwersja do HSL/HSV również byłaby dobrym pomysłem, ale potem zdałem sobie sprawę, że przy ekstremalnych wartościach S & L/V, H nie ma znaczenia, a w środku liczy się najbardziej .

Myślę, że jeśli chcesz prostego rozwiązania, pozostanie w przestrzeni RGB byłoby mądrzejsze. Wykorzystałbym odległość kartezjańską. Jeśli rozważasz kolor R G B przed Ri Gi Bi dla kilku i, chcesz i że minimalizuje

(R - Ri)^2 + (G - Gi)^2 + (B - Bi)^2 
8

najpierw trzeba wybrać th odpowiedniej przestrzeni barw chcesz porównania kolor występuje w (RGB, HSV, HSL, CMYK itp.).

Zakładając, że chcesz wiedzieć, jak blisko dwa punkty w 3-dimenionsal przestrzeni RGB są do siebie, można obliczyć Pitagorasa odległość między nimi, czyli

d2 = (r1 - r2)**2 + (g1 - g2)**2 + (b1 - b2)**2; 

To rzeczywiście daje kwadrat odległość. (Pobieranie pierwiastka kwadratowego nie jest konieczne, jeśli porównujesz tylko wartości kwadratów).

Zakłada się, że chcesz traktować wartości R, G i B jednakowo. Jeśli wolisz wagi poszczególnych składników barwnych, takich jak to, co dzieje się podczas konwersji RGB do skali szarości, trzeba dodać do każdego terminu współczynnik odległości, tj

d2 = 30*(r1-r2)**2 + 59*(g1-g2)**2 + 11*(b1-b2)**2; 

ten zakłada konwersję z popularną RGB do skali szarości 30% czerwony + 59% zielony + 11% niebieski.

Aktualizacja

To ostatnie równanie powinno prawdopodobnie

d2 = (30*(r1-r2))**2 + (59*(g1-g2))**2 + (11*(b1-b2))**2; 
Powiązane problemy