Farbe zu Transparenz (vgl. Gimp/PS)

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
mine
User
Beiträge: 3
Registriert: Mittwoch 19. Juni 2013, 22:08

Hi,
ich bin neu hier, aber nicht neu in Python, habe also schon ein paar Vorkenntnisse.

Wie ich im Titel schon geschrieben, habe ich vor, in einem Bild eine Farbe durch Alpha zu ersetzen, wie das auch in Bildbearbeitungsprogrammen wie Gimp oder Photoshop passiert.

Für diejenigen, die das noch nicht gemacht haben:
Ich wähle eine Farbe aus, z.B. #00FF00. Dann werden alle Bildpunkte abgearbeitet und überall da, wo Grün enthalten ist, wird eben der Grün-Wert abgezogen und der Alpha-Wert auch. Genau dieses Verhalten möchte ich jetzt mit Python erreichen.

Als Hilfsmittel habe ich mir vorerst PIL genommen, später soll das direkt auf RGBA-Ebene laufen, da ich eine .bmp generiere; PIL brauche ich vorerst nur, um durch ein bestehendes Bild zu iterieren.


Meine bisherige Überlegung:
  • Farbe a, Farbe key
  • Wenn a*r = key (also a ein gestreckter Vektor von key ist), dann alpha = 255 * (1-r)
Oder:
  • Farbe a (HSV), Farbe key (HSV)
  • Wenn hue gleich sind, dann alpha = hue_a / hue_key
Aber beide Überlegungen funktionieren nicht so wirklich, also es werden weiterhin nur die Pixel mit exakt der selben Farbe transparent.

Aktuell sieht mein Code so aus (beide Methoden gemixt), in main() wird durch alle Pixel iteriert und denen die Farbe aus makeColor(color) zugewiesen:

Code: Alles auswählen

from colorsys import rgb_to_hsv, hsv_to_rgb
def makeColor(color):
        global key

        o = []

        c = tuple(color[:-1])
        k = tuple(key[:-1])
        
        c = apply(rgb_to_hsv, c)
        k = apply(rgb_to_hsv, k)
        
        a = 1
        if c[0] == k[0]:
                a = 1 - c[2] / float(k[2])
        
        for i in range(0, len(key)):
                o.append(int(a * color[i]))

        return tuple(o)
Habt ihr eine Idee?
anogayales
User
Beiträge: 456
Registriert: Mittwoch 15. April 2009, 14:11

Das macht man normalerweise so, dass man einen Schwellwert in einem sinnvollen Farbraum definiert. Falls dieser Schwellwert nicht überschritten wird, so wird die Farbe eben verändert. Der HSV Farbraum ist da schon Mal ein guter Ansatzpunkt. Jetzt musst du dir noch Gedanken drüber machen für welche Komponente du den Schwellwert zulassen willst. Macht es Sinn eine leichte Abweichung der Farbe zuzulassen oder sind Helligkeitsunterschiede wichtiger? Wie sieht es mit der Farbsättigung aus? Als Übung kannst du ja erst mal einen Schwellwert für nur eine Komponente benutzen.

Außerdem ist deine Implementierung noch nicht so richtig gut. Verwende auf keinen Fall `global key`. Das macht hier keinen Sinn: Übergeb die Variable einfach der Funktion. Außerdem solltest du den Variablen aussagekräftigere Namen geben. Die Umwandlung in tupeln kannst du dir auch sparen. `apply` soll man auch nicht mehr verwenden, schreib einfach c = rgb_to_hsv(c).

Diese Schreibweise sieht man in Python auch sehr selten:

Code: Alles auswählen

        for i in range(0, len(key)):
                o.append(int(a * color[i]))
Das kannst du ganz einfach wie folgt ausdrücken: (Mit der Annahme, dass color und key die gleiche Anzahl an Komponenten hat)

Code: Alles auswählen

        for color_component in color:
                o.append(int(a * color_component))
oder noch besser: Stichwort: List Comprehension

Code: Alles auswählen

o = [int(a*color_component) for color_component in color]
Wenn du Fragen zur Implementierung hast, nur her damit :)

Grüße,
anogayales
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

Hallo mine,

da rgb_to_hsv floats zurück liefert, wirst Du es sehr schwer haben, exakte Übereinstimmung zu finden. »apply« wird wahrscheinlich seit Python 2.0 nicht mehr verwendet. »global« solltest Du genauso schnell aus Deinem Pythonwortschatz verbannen. Einrücktiefe sind 4 Leerzeichen.

Code: Alles auswählen

from colorsys import rgb_to_hsv
def makeColor(color, key, eps=0.01):
    c = rgb_to_hsv(*color[:-1])
    k = rgb_to_hsv(*key[:-1])
    a = 1 if abs(c[0]-k[0])>eps else 1 - c[2]/float(k[2])
    return tuple(int(a*c) for c in color)
mine
User
Beiträge: 3
Registriert: Mittwoch 19. Juni 2013, 22:08

Danke, anogayales & Sirius3, funktioniert gut.
Da bin ich wohl etwas auf dem Schlauch gestanden, danke vielmals :)

P.S.: @Sirius3: Ich nutze noch Python 2.7, da läuft `apply` noch :wink:
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

mine hat geschrieben:P.S.: @Sirius3: Ich nutze noch Python 2.7, da läuft `apply` noch :wink:
Help on built-in function apply in module __builtin__:

apply(...)
apply(object[, args[, kwargs]]) -> value

Call a callable object with positional arguments taken from the tuple args,
and keyword arguments taken from the optional dictionary kwargs.
Note that classes are callable, as are instances with a __call__() method.

Deprecated since release 2.3. Instead, use the extended call syntax:
function(*args, **keywords).
Das Leben ist wie ein Tennisball.
Antworten