Farbähnlichkeit (Allgemeine Programmierfrage)

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Quitte
User
Beiträge: 16
Registriert: Dienstag 12. Mai 2009, 17:49

Hi,

vielleicht kann hier im Python-Forum jemand helfen (obwohl die Frage eher allgemein ist)!

Ich habe zwei Farben im RGB-Format z.B. (255,0,0) , (0,0,255) und möchte Sie auf Ähnlichkeit testen!
Es soll also ein Wert ausgegeben werden, der der augenscheinlichen Ähnlichkeit entspricht (muss nicht perfekt sein)!
D.h. Ich Vergleiche Farbe1 mit Farbe3 und Farbe2 mit Farbe3 und kann dann sagen Farbe1 hat eine höhere Ähnlichkeit zu Farbe3 wie die Farbe2 zur Farbe3 hat!

Die Vergleiche die ich gemacht habe, halten nicht einmal den Grundmischungen (siehe Bild) stand (Vergleich LILA<->Weiss mit GELB<->Weiss bei linearen oder Abstandsquadrat)!
Bild


Hat jemand eine Idee??? Vielleicht ist ein Vergleich im CMYK besser?
ODer vielleicht doch in einem anderen Forum fragen???
Zuletzt geändert von Quitte am Dienstag 15. November 2011, 16:15, insgesamt 1-mal geändert.
Benutzeravatar
Kebap
User
Beiträge: 687
Registriert: Dienstag 15. November 2011, 14:20
Wohnort: Dortmund

Ich schätze, du solltest den RGB-Wert in eine aussagekräftigere Farbskala umrechnen, zB den HSV-Farbraum: http://de.wikipedia.org/wiki/HSV-Farbra ... ahrnehmung
In Fragen der Farbnachstellung wird das HSV-Paradigma gegenüber den Alternativen RGB und CMYK bevorzugt, weil es der menschlichen Farbwahrnehmung ähnelt. So fällt es leichter, die jeweils gewünschte Farbe zu finden
MorgenGrauen: 1 Welt, 8 Rassen, 13 Gilden, >250 Abenteuer, >5000 Waffen & Rüstungen,
>7000 NPC, >16000 Räume, >200 freiwillige Programmierer, nur Text, viel Spaß, seit 1992.
Quitte
User
Beiträge: 16
Registriert: Dienstag 12. Mai 2009, 17:49

Das klingt schon einmal sehr gut, Gucke mir das mal an!
Quitte
User
Beiträge: 16
Registriert: Dienstag 12. Mai 2009, 17:49

Code: Alles auswählen

(255, 0, 0) -->     [000, 001, 255]
(0, 255, 0) -->     [120, 001, 255]
(0, 0, 255) -->     [240, 001, 255]
(0, 0, 0) -->       [000, 000, 000]
(0, 255, 255) -->   [180, 001, 255]
(255, 0, 255) -->   [300, 001, 255]
(255, 255, 0) -->   [060, 001, 255]
(255, 255, 255) --> [000, 000, 255]
Und nun?? Wie den Vergleich genau anstellen?
Abstand berechnen mit Interpretation des Farbraum als Zylinder???
deets

Ja, denn du musst ja fuer hohe V oder S (bzw. niedrige, wie rum auch immer) dafuer Sorge tragen, dass der H-Wert an Signifikanz verliert. An der Oberflaeche des Zylinders ist der wichtig, je mehr zur Spitze bzw. Mittelachse es geht, desto weniger. Da findet sich bestimmt was online...
Quitte
User
Beiträge: 16
Registriert: Dienstag 12. Mai 2009, 17:49

Das sieht noch besser aus: http://de.wikipedia.org/wiki/Lab-Farbraum
Die Koordinaten des L*a*b*-Farbortes orientieren sich an den physiologischen Eigenschaften der menschlichen Wahrnehmung...
Der wesentliche Vorteil ist die visuelle Gleichabständigkeit: die geometrisch berechenbaren Abstände zweier Farborte im Lab-System entsprechen gut angenähert visuell wahrgenommenen Farbabständen.
deets

Cool, kannte ich noch gar nicht.
Quitte
User
Beiträge: 16
Registriert: Dienstag 12. Mai 2009, 17:49

Irgendwo ist noch der Wurm drin!

Code: Alles auswählen

def rgb2xyz(farbe):
    X = 0.4124564*farbe[0] + 0.3575761*farbe[1] + 0.1804375*farbe[2]
    Y = 0.2126729*farbe[0] + 0.7151522*farbe[1] + 0.0721750*farbe[2]
    Z = 0.0193339*farbe[0] + 0.1191920*farbe[1] + 0.9503041*farbe[2]
    return [X,Y,Z]

def xyz2lab(farbe):
    #P/P_n - Werte für große und kleine Bereiche definiert
    werte = farbe[:]
    faks = [0.95,1,1.09]
    for i in range(3):
        werte[i] = float(werte[i])/faks[i]
        if werte[i] * 24389 < 216:
            werte[i] = float(1)/116 * (float(24389)/27 * werte[i] + 16)

    
    l = 116* pow( float(werte[1]) , (1./3) ) - 16
    a = 500* ( pow( float(werte[0])/0.95 , (1./3) ) - pow( float(werte[1]) , (1./3) ) )
    b = 200* ( pow( float(werte[1]) , (1./3) ) - pow( float(werte[2])/1.09 , (1./3) ) )
    return [l,a,b]


def farbabstand(f1,f2):
    f1 = xyz2lab(rgb2xyz(f1))
    f2 = xyz2lab(rgb2xyz(f2))

    erg = 0
    for i in range(3):
        erg += pow(f1[i] - f2[i], 2)

    return int(erg)

print farbabstand([0,0,0],[255,255,255])
print farbabstand([0,0,255],[0,0,0])
Ausgabe:
460208
766287
:K

Wo ist mein Fehler???
http://de.wikipedia.org/wiki/Lab-Farbraum
anogayales
User
Beiträge: 456
Registriert: Mittwoch 15. April 2009, 14:11

Musst du da nicht noch die Wurzel ziehen?
Quitte
User
Beiträge: 16
Registriert: Dienstag 12. Mai 2009, 17:49

Ich möchte nur Ordinalsskala haben! Ich vergleiche die Farben nur und messe keinen abstand!
Wenn a^2 > b^2 dann ist auch sqrt(a^2) > sqrt(b^2)
Wurzel ziehen ist deshalb beim reinen Vergleich nicht nötig!

Ob da 460208 und 766287 oder 678 und 875 steht ist egal!
Das würde bei beiden bedeuten das Weis<->Schwarz ähnlichere Farben als Blau<->Schwarz sind, was nicht stimmt!

Aber wo ist der Fehler? Ich vermute eher einen Denkfehler!
anogayales
User
Beiträge: 456
Registriert: Mittwoch 15. April 2009, 14:11

gibt es für sowas keine Referenzimplementierung? Am besten da mal gucken.
BlackJack

Weil mir die ``for i in xrange(3):``-Zeilen nicht gefallen habe ich es mal ohne geschrieben (ungetestet):

Code: Alles auswählen

from itertools import imap, izip


def cube_root(x):
    return pow(x, 1.0 / 3)


def xyz2lab(farbe):
    
    def f(value, factor):
        """P/P_n - Werte für große und kleine Bereiche definiert."""
        result = value / factor
        if result < 216.0 / 24389:
            result = (24289 * result + 432) / 3132.0
        return result
    
    x, y, z = imap(f, farbe, [0.95, 1.0, 1.09])
    
    return (
        116 * cube_root(y) - 16,
        500 * (cube_root(x / 0.95) - cube_root(y)),
        200 * (cube_root(y) - cube_root(z / 1.09))
    )


def rgb2lab(colour):
    return xyz2lab(rgb2xyz(colour))


def farbabstand(f1, f2):
    return int(sum((a - b)**2 for a, b in izip(rgb2lab(f1), rgb2lab(f2))))
Sollte natürlich nichts am Ergebnis ändern.
Quitte
User
Beiträge: 16
Registriert: Dienstag 12. Mai 2009, 17:49

So klappt es
(habe das direkt aus einem Javaprogramm Übersetzt)

Code: Alles auswählen

def rgb2lab(farbe):
    R=farbe[0]
    G=farbe[1]
    B=farbe[2]
    
    eps = 216./24389
    k = 24389./27
    Xr = 0.964221
    Yr = 1.0
    Zr = 0.825211

    r = float(R)/255
    g = float(G)/255
    b = float(B)/255
    if r <= 0.04045:
        r = r/12
    else:
        r = pow((r+0.055)/1.055,2.4)

    if g <= 0.04045:
        g = g/12
    else:
        g = pow((g+0.055)/1.055,2.4)

    if b <= 0.04045:
        b = b/12
    else:
        b = pow((b+0.055)/1.055,2.4)

    X =  0.436052025*r     + 0.385081593*g + 0.143087414 *b
    Y =  0.222491598*r     + 0.71688606 *g + 0.060621486 *b
    Z =  0.013929122*r     + 0.097097002*g + 0.71418547  *b
		
    xr = X/Xr
    yr = Y/Yr
    zr = Z/Zr
				
    if xr > eps:
        fx =  pow(xr, 1./3)
    else:
        fx = ((k * xr + 16) / 116)
		 
    if yr > eps:
        fy =  pow(yr, 1./3)
    else:
        fy = ((k * yr + 16) / 116.)

    if zr > eps:
        fz =  pow(zr, 1./3)
    else:
        fz = ((k * zr + 16) / 116)
	
    Lss = ( 116. * fy ) - 16
    ass = 500.*(fx-fy)
    bss = 200.*(fy-fz)
		
    lab = ( 2.55*Lss + .5 , ass + .5 , bss + .5 )
    return lab
Habe damit ein Mosaik-Programm geschrieben! (Großes Bild aus kleinen Bildern erstellen)
Ergebnisse sind deutlich besser bei metapixel und man hat mehr Parameter zum einstellen (insbesondere die Größe der Einzelbilder ohne Verzerrung)
Ich kann mir nun ein paar hundert Einzelfotos bestellen und dann das Mosaikbild per Hand aus einzelnen Bilder erstellen (Programm gibt die Reihenfolge)!
Ist deutlich cooler als einfach ein Poster des Mosaik-Bildes zu bestellen (was mit dem Programm aber natürlich auch geht)

Auf alle Fälle Danke für die Hilfen!
Antworten