Obrázky (reprezentace, generování, úpravy) IB111 Úvod do programování 2016 1 / 67 2 / 67 Účel přednášky procvičení základních konstrukcí z jiného pohledu propojení programování a matematiky téma „reprezentace dat procvičení „čtení kódu podklad pro zajímavé cvičení 3 / 67 Poznámka k efektivitě, obrázkům ukázky programů v přednášce: snaha o čitelnost programů neefektivní (pomalé): algoritmy technická realizace (např. putpixel vs load + pixel access object) nízká / rozličná kvalita obrázků – čistě pragmatické důvody (nepříliš velké PDF), žádná skrytá pointa 4 / 67 Další zdroje, náměty obrázky, zvuk, video: kniha Introduction to Computing and Programming in Python, A Mutlimedia Approach, M. J. Guzdial, B. Ericson. http://coweb.cc.gatech.edu/mediaComp-teach 5 / 67 Reprezentace obrázků Bitmapová grafika Vektorová grafika (5,3) (5,27) (5,15) (25,3) (25,27) 6 / 67 Reprezentace barev více barevných modelů (aditivní, subtraktivní) budeme používat aditivní model RGB – red, green, blue každá složka = hodnota 0-255 (8 bitů, 1 byte) barva = trojice, např. (15, 255, 100) 7 / 67 Knihovny (moduly) v Pythonu knihovna poskytuje rozšiřující funkcionalitu zdroje knihoven: standardní distribuce (např. math, turtle) separátní instalace (např. numpy) vlastní knihovny použití knihoven: import knihovna – následná volání knihovna.funkce() import knihovna as nazev from knihovna import funkce from knihovna import * (nedoporučeno) 8 / 67 Proč nepoužívat „import * from X import * V malém programu nemusí vadit, ale ve větších projektech považováno za velmi špatnou praxi. „nepořádek v jmenném prostoru kolize, přepis překlepy se mohou chovat magicky složitější interpretace chybových hlášek Python Zen: Explicit is better than implicit. 9 / 67 Knihovna Image knihovna pro práci s bitmapovými obrázky velmi bohatá funkcionalita použijeme jen základní operace: new – vytvoření obrázku open, convert – otevření obrázku, konverze na RGB mód getpixel – zjištění barvy bodu putpixel – změna barvy bodu size – velikost obrázku show, save – zobrazení, uložení 10 / 67 Knihovna Image – technické poznámky Python Imaging Library (PIL): jen pro Python 2 http://www.pythonware.com/products/pil/ implementace Pillow (i pro Python 3): https://pypi.python.org/pypi/Pillow/2.1.0 from PIL import Image 11 / 67 N-tice reprezentace souřadnic a barev pomocí n-tic (tuple) podobné jako seznamy, ale neměnitelné; zápis pomocí kulatých závorek u obrázků typicky: souřadnice: (x, y) barva: (r, g, b) 12 / 67 Image demo def demo(): im = Image.new("RGB", (20,20), (255,255,255)) # model, velikost, barva pozadi im.putpixel((10,10), (0,0,0)) im.putpixel((8,7), (255,0,0)) im.putpixel((5,13), (100,255,105)) im.show() im.save("demo.png") 13 / 67 Geometrické útvary Napište programy pro generování následujících útvarů: čtverec trojúhelník kruh elipsa spirála 14 / 67 Kruh def disc(a = 150, r = 50): im = Image.new("RGB", (a, a), (255, 255, 255)) for x in range(a): for y in range(a): if XXX: im.putpixel((x, y), (0, 0, 0)) im.show() 15 / 67 Kruh def disc(a = 150, r = 50): im = Image.new("RGB", (a, a), (255, 255, 255)) for x in range(a): for y in range(a): if (x-a/2)**2 + (y-a/2)**2 < r**2: im.putpixel((x, y), (0, 0, 0)) im.show() 16 / 67 Barevný kruh 17 / 67 Barevný kruh Barvu „namícháme podle vzdálenosti od středu kruhu: d = math.sqrt((x-a/2)**2 + (y-a/2)**2) if d < r: c = int(255*d/r) im.putpixel((x,y), (c,0,255-c)) 18 / 67 Barevné kruhy 19 / 67 Přidání náhodného kruhu do obrázku def add_random_disc(im): (width, height) = im.size r = random.randint(8, min(width, height) // 6) sx = random.randint(r+1, width-r-1) sy = random.randint(r+1, height-r-1) color = (random.randint(0,255), random.randint(0,255), random.randint(0,255)) for x in range(width): for y in range(height): if (x-sx)**2 + (y-sy)**2 < r**2: im.putpixel((x,y), color) 20 / 67 Námět na procvičení 21 / 67 Geometrické obrazce 22 / 67 Základní princip potřebujeme plynulý přechod mezi bílou a černou jakou matematickou funkci využijeme? 23 / 67 Základní princip potřebujeme plynulý přechod mezi bílou a černou jakou matematickou funkci využijeme? sinus – hodnoty mezi -1 a 1, perioda 2π potřebujeme – hodnoty mezi 0 a 255, perioda (např.) 20 23 / 67 Pruhy def strips(size = 150, count = 5): im = Image.new("RGB", (size, size)) for x in range(size): for y in range(size): z = math.sin(count * 2 * math.pi * x/size) shade = int(255 * (z + 1) / 2) im.putpixel((x,y), (shade, shade, shade)) im.show() 24 / 67 Vzory II 25 / 67 Mandelbrotova množina 26 / 67 Mandelbrotova množina z1 = 0, c = x + yi je konstanta (komplexní číslo) definujeme posloupnost zn+1 = z2 n + c c patří do Mandelbrotovy množiny ⇔ tato posloupnost je omezená 27 / 67 Mandelbrotova množina – detail Zdroj: Wikipedia Video zoom: http://www.youtube.com/watch?v=gEw8xpb1aRA 28 / 67 Mandelbrotova množina – kód _ = ( 255, lambda V ,B,c :c and Y(V*V+B,B, c -1)if(abs(V)<6)else ( 2+c-4*abs(V)**-0.4)/i ) ;v, x=1500,1000;C=range(v*x );import struct;P=struct.pack;M,\ j =’ 55 / 67 Hvězda 56 / 67 def star(n = 10, length = 100): svg_header() center_x = length * 1.5 center_y = length * 1.5 step = length / n for i in range(n + 1): svg_line(center_x + i*step, center_y, center_x, center_y + (n-i)*step) svg_line(center_x - i*step, center_y, center_x, center_y + (n-i)*step) svg_line(center_x + i*step, center_y, center_x, center_y - (n-i)*step) svg_line(center_x - i*step, center_y, center_x, center_y - (n-i)*step) svg_finish() 57 / 67 Kompaktnější zápis def star(n = 10, length = 100): svg_header() center_x = length * 1.5 center_y = length * 1.5 step = length / n for i in range(n + 1): for dx, dy in [(-1,-1), (-1,1), (1,-1), (1,1)]: svg_line(center_x + dx*i*step, center_y, center_x, center_y + dy*(n-i)*step) svg_finish() 58 / 67 Variace na hvězdu 59 / 67 Vlastní knihovna pro želví grafiku želví grafika – používána knihovna turtle vytvořme vlastní “knihovnu” s vykreslováním do SVG jen základní příkazy: forward(length) left(angle), right(angle) save(filename) 60 / 67 Princip implementace stav želvy: souřadnice x,y a aktuální natočení heading vykreslený obrazec: seznam souřadnic 61 / 67 Implementace I x = 50 y = 50 heading = 0 lines = [] def left(angle): global heading heading -= angle def right(angle): global heading heading += angle 62 / 67 Implementace II def forward(d): global x global y nx = x + d * math.cos(heading * math.pi / 180) ny = y + d * math.sin(heading * math.pi / 180) lines.append((x, y, nx, ny)) x, y = nx, ny 63 / 67 Poznámky jde o názornou ukázku principů, nikoliv dobrou knihovnu: příliš malá funkcionalita chybí dokumentace nevhodné použití globálních proměnných – vhodné pro objektovou reprezentaci 64 / 67 class Turtle: def __init__(self): self.x = 50 self.y = 50 self.heading = 0 self.lines = [] def left(self, angle): self.heading -= angle def right(self, angle): self.heading += angle def forward(self, d): nx = self.x + d * math.cos(self.heading * math.pi / 180 ny = self.y + d * math.sin(self.heading * math.pi / 180 self.lines.append((self.x, self.y, nx, ny)) self.x, self.y = nx, ny 65 / 67 Absolutní vs relativní vykreslování (souřadnice vs želva) 66 / 67 Shrnutí ukázka elementární práce s grafikou bitmapová – Image, putpixel, getpixel vektorová – SVG, line využití základních konstrukcí (vesměs vnořené for cykly), trocha matematiky 67 / 67