IB111 Základy programování Radek Pelánek 2018 2/74 < [f? ► < -e ► < -ž ► š o q, o 3/74 Účel prednáš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í 4/74 Poznámka k efektivitě, obrázkům ukázky programů v přednášce: • snaha o čitelnost programů • neefektivní (pomalé): • algoritmy o 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 )alšŕ 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 Reprezentace obrázků Bitmapová grafika Vektorová grafika • 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) hovna 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 mód • getpixel - zjištění barvy bodu • putpixel - změna barvy bodu • size - velikost obrázku • show, save - zobrazení, uložení 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 10/74 • 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) 11/74 def demo(): im = Image.new("RGB", (20, 20), (255, 255, 255)) # model, velikost, barva pozadí 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") Geometrické útvary Napište programy pro generovaní následujících útvarů čtverec trojúhelník kruh elipsa spirála 13/74 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() 14/74 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() 15/74 16/74 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)) Pridaní 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) 19/74 21/74 - Základní princip • potřebujeme plynulý přechod mezi bílou a černou • jakou matematickou funkci využijeme? 22/74 - 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 2tt • potřebujeme - hodnoty mezi 0 a 255, perioda (např.) 20 22/74 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+l)/2) im.putpixel((x,y), (shade, shade, shade)) im.show() 23/74 < [f? ► < -e ► < -ž ► š o q, o 24/74 25/74 Mandelbrotova množina • zi = 0, c = x + yi je konstanta (komplexní číslo) • definujeme posloupnost z„+i = z2n + c • c patří do Mandelbrotovy množiny <^> tato posloupnost je omezená andelbrotova množina - detail Zdroj: Wikipedia Video zoom: http://www.youtube.com/watch?v=gEw8xpblaRA 21 jlA andelbrotova množina - kód = c 255, lambda V ,B,c :c and Y(V*V+B,B, c -l)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 =5 (x-a/2)**2: im.putpixel((x, y), (0, 0, 0)) im.show() make_image1() def make_image2(a=160): im = Image.new("RGB", (a, a), (255, 255, 255)) for x in range(a): for y in range(a): if (x // 20 + y // 20) °/0 2 == 0: im.putpixel((x, y), (0, 0, 0)) im.show() make_image2() 44/74 def transform(filename): im = Image.open(filename) im = im.convert("RGB") width, height = im.size for x in range(width): for y in range(height): (r, g, b) = im.getpixel((x, y)) g, b = int(g*0.8), int(b*0.8) r = min(int(r*1.4), 255) im.putpixel((x, y), (r, g, b)) im.show() 45/74 46/74 47/74 Histogram variace na téma „frekvenční analýza" "■ les.jpg-1.0 (RGB, 1 vrstva] 3&9xZ92 - CIMP Soubor Upravit Vybrat Zobrazení Obrázek Vrstva Barvy Nástro m.......\w.......\m iii"........ • an ..... U px : 100% * Pozadí (1,3 MB) Histogram Histogram Pozadí Kanál: 3/Zelená 0 Str. hodnota: 121,5 Směr, odch.: 44.5 Median: 122.0 Pixelů: 1135BB Počet: 113566 Procento: 100.0 48/74 Histogram - textový výpis 0 - 19: 0.3 % 20 - 39: 3.5 % 40 - 59: 6.3 % 60 - 79: 8.3 % 80-99: 12.7 % 100 - 119: 17.1 % 120 - 139: 18.5 % 140 - 159: 15.2 % 160 - 179: 9.0 % 180 - 199: 4.0 % 200 - 219: 1.8 % 220 - 239: 1.1 °/„ 240 - 259: 2.2 °/„ (implementace - doporučené cvičení) Další náměty na úpravy • změna velikosti obrázku • převod do stupňů šedi • rozmazání (blur), detekce hran • ... další věci co umí váš grafický program 50/74 Pořádek v umění http://www.ted.com/talks/ursus_wehrli_tidies_up_art.html 51/74 Pořádek (nejen) v umění 52/74 Pořádek v umění - pixel po pixelu 53/74 Razení pixelů podle barvy • vytvoříme seznam všech použitých barev - seznam trojic [(0, 150, 20), (255,255,255), (0, 0, 255), ...] • seznam seřadíme • barvy umístíme do obrázku 54/'74 def tidy_up(filename): im = Image.open(filename) im = im.convert("RGB") width, height = im.size pixels = [] for x in range(width): for y in range(height): pixels.append(im.getpixel((x, y))) pixels.sort() new_im = Image.new("RGB", (width, height)) for y in range(height): for x in range(width): new_im.putpixel((x, y), pixels [y*width+x]) new_im. showQ 55/74 Razení pixel • pixely je seznam trojic (r, g, b) • sort() používá „lexikografické" řazení • pokud chceme „řazení dle součtu" (intenzity) nahradíme pixels.sort () za: pixels = sorted(pixels, key=lambda c: -(c[0]+c [1]+c [2])) 57/74 Pořádek v umění - námět Zkuste další způsoby řazení: • po řádcích / sloupcích • po „čtverečcích" • podle jiného kritéria • „gradient" po úhlopříčce 58/74 Scalable Vector Graphics (SVG) • vektorový formát založený na XML • snadný způsob vytváření obrázků v jakémkoliv jazyce (generujeme prostý text) • prohlížení: např. webový prohlížeč • ruční editování: např. Inkscape • převod na bitmapu: např. convert (ImageMagick) 59/74 SVG příklad ") s = ;M) f. closeO 69/74 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 - lepší přes objektovou reprezentaci 70/74 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 71/74 (souřadnice vs želva) 72/74 Jak vykreslíte tyto obrázky? • 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 74/74