Termin 5: Medienprogrammierung in Python – Bildverarbeitung (2) Grundlagen der Informatik Wintersemester 2006/07 Prof. Bernhard Jung Übersicht Medienprogrammierung mit Python / JES z.B. Erzeugung von Negativen, Grauwertkonvertierung, … Jes-Debugger for-Schleifen in Python if-Anweisung in Python Hauptlernziele: • Verstehen zentraler Kontrollstrukturen der imperativen Programmierung • for – Schleife • if … else (bedingte Anweisung) • Digitale Medien: • Verständnis von Farb-, Grauwert-, und Binärbildern Prof. B. Jung Grundlagen der Informatik, WS 2006/07 1 Wiederholung – Beispiel: Ändern von Pixel-Werten >>> filename = pickAFile() >>> mypic = makePicture(filename) >>> show(mypic) >>> setColor(getPixel(mypic, 10, 100),yellow) >>> setColor(getPixel(mypic, 11, 100),yellow) >>> setColor(getPixel(mypic, 12, 100),yellow) >>> setColor(getPixel(mypic, 13, 100),yellow) >>> setColor(getPixel(mypic, 14, 100),yellow) >>> setColor(getPixel(mypic, 15, 100),yellow) >>> repaint(mypic) jetzt 6 gelbe Pixel hier Prof. B. Jung Grundlagen der Informatik, WS 2006/07 Bildverarbeitung mit Schleifen - Definition eines Python-Skripts def decreaseRed(picture): for p in getPixels(picture): value = getRed(p) setRed(p, value * 0.5) Verringerung des Rot-Anteils in jedem Pixel des Bilds Æ for-Schleife Prof. B. Jung Grundlagen der Informatik, WS 2006/07 2 Schleifen in Python Aufbau von Schleifen for – Schlüsselwort, Name der Anweisung Indexvariable p Name der Variable kann frei gewählt werden in – Schlüsselwort, fester Teil der Anweisung Eine Sequenz bzw. Ausdruck der eine Sequenz liefert getPixels(picture) liefert Liste aller Pixel zur Erinnerung (Vorlesung 3): Sequenz = Liste, String, oder Tupel Doppelpunkt ':' Rumpf der Schleife eingerückt hier besteht der Rumpf aus 2 Anweisungen Prof. B. Jung Grundlagen der Informatik, WS 2006/07 Schleifen in Python for <variable> in <sequenz>: <anweisungen> for i in ['a','b','c']: print i 1. 2. 3. Schleifendurchlauf: i = 'a' Æ Ausgabe: a Schleifendurchlauf: i = 'b' Æ Ausgabe: b Schleifendurchlauf: i = 'c' Æ Ausgabe: c Prof. B. Jung Grundlagen der Informatik, WS 2006/07 3 Schleifen in Python for <variable> in <sequenz>: <anweisungen> for i in [4,6,9]: print i 1. 2. 3. Schleifendurchlauf: i = 4 Æ Ausgabe: 4 Schleifendurchlauf: i = 6 Æ Ausgabe: 6 Schleifendurchlauf: i = 9 Æ Ausgabe: 9 Prof. B. Jung Grundlagen der Informatik, WS 2006/07 Der JES-Watcher (Debugger) Start des Watchers Prof. B. Jung Hinzufügen einer zu beobachtenden Variablen (hier: i) Grundlagen der Informatik, WS 2006/07 4 Beispiel Bildverarbeitung – Generierung von Sonnenuntergängen Idee: Blau- und Grün-Anteile im Bild reduzieren (Rot wird so dominanter) def makeSunset(picture): for p in getPixels(picture): value=getBlue(p) setBlue(p,value*0.7) value=getGreen(p) setGreen(p,value*0.7) Prof. B. Jung Grundlagen der Informatik, WS 2006/07 Beispiel Bildverarbeitung – Generierung von Sonnenuntergängen die zuvor definierte Funktion makeSunset() ist natürlich auf beliebige Bilder anwendbar dazu muss nur die Funktion nur mit einem anderen Input-Parameter aufgerufen werden def makeSunset(picture): for p in getPixels(picture): value=getBlue(p) setBlue(p,value*0.7) value=getGreen(p) setGreen(p,value*0.7) tu-baf.jpg Prof. B. Jung Grundlagen der Informatik, WS 2006/07 5 Die range()-Funktion range()-Funktion Generierung von Listen mit Elementen zwischen den beiden Input-Parametern optionaler dritter Input-Parameter bestimmt Inkrement >>> print range(1,4) [1, 2, 3] >>> print range(-1,3) [-1, 0, 1, 2] >>> print range(1,10,2) [1, 3, 5, 7, 9] Prof. B. Jung Grundlagen der Informatik, WS 2006/07 Beispiel: range()-Funktion Prof. B. Jung Grundlagen der Informatik, WS 2006/07 6 Indizierung von Pixeln Bild: Matrix von Pixeln Breite von Bildern: w = getWidth(picture) Höhe von Bildern: h = getHeight(picture) Pixel können über ihren Index (x,y) referenziert werden pixel = getPixel( picture, x, y) Æ Bildverarbeitung mittels geschachtelte Schleifen … Prof. B. Jung Grundlagen der Informatik, WS 2006/07 Geschachtelte Schleifen Schachtelung von Schleifen: Rumpf einer Schleife ist wiederum eine Schleife def increaseRed2(picture): for x in range(1, getWidth(picture)+1 ): for y in range(1, getHeight(picture)+1 ): px = getPixel(picture,x,y) value = getRed(px) setRed(px, value*1.1) hier: spaltenweise Bearbeitung der Pixel Verarbeitungsreihenfolge der Indices Prof. B. Jung (1,1), (1,2), (1,3) …. (2,1), (2,2), (2,3), … (3,1), (3,2), … … Grundlagen der Informatik, WS 2006/07 7 Farbersetzung in Teilbereichen von Bildern def increaseRedInRange(picture, xmin, ymin, xmax, ymax): for x in range(xmin, xmax+1): for y in range(ymin, ymax+1): px = getPixel(picture,x,y) value = getRed(px) setRed(px, value*1.2) >>> increaseRedInRange(pic2, 78, 41, 158, 59) Auswahl des Bildbereichs mittels MediaTools Prof. B. Jung Grundlagen der Informatik, WS 2006/07 Beispiel Bildverarbeitung – Erzeugung von Negativen R, G, B-Werte im Bereich 0 .. 255 Negativ eines Pixels, z.B. (5,10,25): Negativ eines Bilds: Negativ aller Pixel Æ (255-5, 255-10, 255-25) = (250, 245, 230) def negative(picture): for px in getPixels(picture): red=getRed(px) green=getGreen(px) blue=getBlue(px) negColor=makeColor( 255-red, 255-green, 255-blue) setColor(px,negColor) Prof. B. Jung Grundlagen der Informatik, WS 2006/07 8 Grauwertbilder Farbbilder: Grauwertbilder Drei Farbkanäle (RGB) 8 Bit = 1 Byte (0…255) pro Kanal Darstellung von insgesamt 224 Farben 1 Farbkanal zu 8 Bit = 1 Byte d.h. Darstellung von 28 = 256 Grauwerten Konvertierung Farb- Æ Grauwertbild z.B. Luminanz = Prof. B. Jung Grundlagen der Informatik, WS 2006/07 Konvertierung zu Grauwertbildern in JES Echte Grauwertbilder: Pro Pixel 1 Farbwert In JES: setze R,G,B auf denselben Farbwert, z.B. def grayscale(picture): for p in getPixels(picture): intensity = (getRed(p) + getGreen(p) + getBlue(p)) / 3 setColor(p,makeColor(intensity,intensity,intensity)) Prof. B. Jung Grundlagen der Informatik, WS 2006/07 9 Konvertierung zu Grauwertbildern Bisherige Methode zur Berechnung des Grauwerts von Pixeln ist nicht optimal Psychologische Experimente legen nahe, dass Wahrnehmung von Farben bzgl. Luminanz unterschiedlich ist z.B. wird blau als "dunkler" wahrgenommen als rot auch bei gleicher physikalischer Lichtintensität Grauwert-Konvertierung mit wahrnehmungspsychologisch fundierter Gewichtung: def grayscaleweighted(picture): for px in getPixels(picture): newRed = getRed(px) * 0.299 newGreen = getGreen(px) * 0.587 newBlue = getBlue(px) * 0.114 luminance = newRed+newGreen+newBlue setColor(px,makeColor(luminance,luminance,luminance)) Prof. B. Jung Grundlagen der Informatik, WS 2006/07 Grauwertkonvertierung einfache Grauwertkonvertierung Prof. B. Jung gewichtete Grauwertkonvertierung Grundlagen der Informatik, WS 2006/07 10 Beispiel: Farbauffrischung für Dächer - Bedingtes Verändern von Pixelwerten Ziel: Intensivierung des Rot-Anteils von Dächern Idee: Erhöhung des Rotanteils von Pixeln aber nur wenn diese schon rötlich sind Æ if-Anweisung def intensifyRed(picture): for p in getPixels(picture): value=getRed(p) if ( value > 180 ): setRed(p,value*1.5) Prof. B. Jung Grundlagen der Informatik, WS 2006/07 Python: If-Anweisung vgl. Programmablaufplan (VL 2) if ( <Bedingung> ): <Anweisungen> if ( <Bedingung> ): <Anweisungen> else: <Anweisungen> ja A1 B nein A2 Aufbau: if – Schlüsselwort Bedingung – kann zu True oder False evaluiert werden auch komplexe Bedingungen, z.B. verknüpft mit and if ( a >5 and a <10): Doppelpunkt Anweisungen, die ausgeführt werden, falls Bedingung gilt optionaler else-Teil Prof. B. Jung Grundlagen der Informatik, WS 2006/07 11 Beispiel: if … else Ziel: Überprüfung, welche Pixel bei der beabsichtigten bedingten Pixeleinfärbung überhaupt eingefärbt werden wurden Zeichne ursprüngl. "rötliche" Pixel weiß, alle anderen schwarz Æ Resultierendes Bild hat nur noch zwei Farben (schwarz/weiß) Æ "Binärbild" def intensifyRed3(picture): for p in getPixels(picture): value=getRed(p) if ( value > 180 ): setColor(p, white) else: setColor(p, black) Æ alle Dächer, aber nicht nur! Æ bessere Bedingung für Dachpixel??? Prof. B. Jung Grundlagen der Informatik, WS 2006/07 "Posterisierung" – Reduktion der Anzahl der Farben in einem Bild Prof. B. Jung Grundlagen der Informatik, WS 2006/07 12 "Posterisierung" - Methode Ganze Bereiche von Farb-Anteilen werden auf einen bestimmten Farbanteil abgebildet z.B. falls Rotanteil < 64 dann setze Rotanteil = 31 z.B. falls Rotanteil zwischen 64 und 128 dann Rotanteil = 95 … Implementierung durch Reihe von if-Anweisungen Resultierendes Bild hat deutlich weniger Farben Prof. B. Jung Grundlagen der Informatik, WS 2006/07 "Posterisierung" def posterize(picture): #loop through the pixels for p in getPixels(picture): #get the RGB values red = getRed(p) green = getGreen(p) blue = getBlue(p) #check and set red values if(red < 64): setRed(p, 31) if(red > 63 and red < 128): setRed(p, 95) if(red > 127 and red < 192): setRed(p, 159) if(red > 191 and red < 256): setRed(p, 223) Prof. B. Jung #check and set green values if(green < 64): setGreen(p, 31) if(green > 63 and green < 128): setGreen(p, 95) if(green > 127 and green < 192): setGreen(p, 159) if(green > 191 and green < 256): setGreen(p, 223) #check and set blue values if(blue < 64): setBlue(p, 31) if(blue > 63 and blue < 128): setBlue(p, 95) if(blue > 127 and blue < 192): setBlue(p, 159) if(blue > 191 and blue < 256): setBlue(p, 223) Grundlagen der Informatik, WS 2006/07 13 Kommentare in Python Programmzeilen, die mit '#' beginnen sind Kommentare #loop through the pixels for p in getPixels(picture): … Kommentare können auch in der Mitte von Programmzeilen beginnen setRed(pixel, 255) # update Rot-Anteil des Pixels Kommentare in Programmen dienen der Dokumentation des Codes Kommentare werden vom Python-Interpreter nicht ausgewertet Prof. B. Jung Grundlagen der Informatik, WS 2006/07 def getIntensity(p): sum = getRed(p) + getGreen(p) + getBlue(p) average = float(sum) / 3 # Bereich 0.0 .. 255.0 return average / 255 # Bereich 0.0 .. 1.0 # pink = (255, 128, 128) # moduliere mit Intensität des Original-Pixels def makePinkish(p): i = getIntensity(p) setRed(p, int(255 * i * 3) ) setGreen(p, int( getGreen(p) * i * 3) ) setBlue(p, int( getBlue(p) * i * 3) ) … und noch ein Beispiel (codiert mit viel Ausprobieren) def isGreenish(p): r = getRed(p) g = getGreen(p) b = getBlue(p) if g > r + 15 and g + 11 > b: return 1 return 0 def replaceGreenishInRange(picture, xmin, xmax, ymin, ymax): for x in range(xmin,xmax): for y in range(ymin,ymax): pix = getPixel(picture,x,y) if isGreenish(pix): makePinkish(pix) return picture 14