# --- # jupyter: # jupytext: # formats: ipynb,py:percent # text_representation: # extension: .py # format_name: percent # format_version: '1.3' # jupytext_version: 1.14.0 # kernelspec: # display_name: Python 3 (ipykernel) # language: python # name: python3 # --- # %% [markdown] toc=true slideshow={"slide_type": "notes"} #

Table of Contents

#
# %% [markdown] slideshow={"slide_type": "slide"} # # Fondamenti di Programmazione # # # **Andrea Sterbini** # # lezione 12 - 14 novembre 2022 # %% [markdown] slideshow={"slide_type": "subslide"} # # RECAP: # - **query in un gruppo di files con tr-idf (term frequency - inverse document frequency)** # - files **json** # - files **yaml** # - lettura di pagine e file da web con **requests** # %% [markdown] slideshow={"slide_type": "subslide"} # # OGGI: immagini # # - sono griglie rettangolari di pixel (**pic**ture **el**ement) colorati # - ogni posizione a coordinate x,y contiene un colore # - **[RGB](https://en.wikipedia.org/wiki/RGB_color_model)** è un modo di codificare i colori (altri: HSV/L/B, CMYK) # - R: luminosità della componente rossa (red) # - G: luminosità della componente verde (green) # - B: luminosità della componente blu (blue) # # Questi valori in genere sono codificati in un byte [0 .. 255] quindi un pixel occupa 24 bit (16M colors) # %% IMMAGINI come matrici di pixel slideshow={"slide_type": "subslide"} # con valori tra 0 e 255 compresi (1 byte) # definiamo qualche colore black = 0, 0, 0 white = 255, 255, 255 red = 255, 0, 0 green = 0, 255, 0 blue = 0, 0, 255 cyan = 0, 255, 255 yellow= 255, 255, 0 purple= 255, 0, 255 grey = 128, 128, 128 # %% [markdown] slideshow={"slide_type": "subslide"} # ## Immagine = matrice di pixel # - per semplicità usiamo una lista di liste # - la lista esterna è l'immagine, che contiene righe orizzontali di pixel # - ciascuna riga di pixel è una lista # - tutte le righe hanno la stessa lunghezza # - le righe nella immagine sono disposte dall'alto in basso (l'asse Y va in giù) # - ciascuna riga va da sinistra a destra (l'asse X va a destra) # %% [markdown] slideshow={"slide_type": "subslide"} # ## Creazione di una immagine/matrice monocolore # ### nel modo sbagliato # %%% costruire una immagine WxH di un dato colore slideshow={"slide_type": "fragment"} import images def crea_immagine_errata(larghezza, altezza, colore): riga = [ colore ] * larghezza img = [ riga ] * altezza return img img2 = crea_immagine_errata(30, 40, blue) img2[5][7] = red # Coloro un solo pixel images.visd(img2) # e trovo una colonna rossa!!! ## LAVAGNA! # %% [markdown] slideshow={"slide_type": "subslide"} # ## PERCHE'? # **`riga = [ colore ] * larghezza`** costruisce una lista di RIFERIMENTI ad un unico colore # # **`img = [ riga ] * altezza`** costruisce una lista di RIFERIMENTI ad una unica riga # # Mentre la prima va bene perchè tutti i colori sono tuple, immutabili # # La seconda NO perchè vogliamo che le righe siano modificabili indipendentemente # # ![](creazione.png) # %% [markdown] slideshow={"slide_type": "subslide"} # ### Nel modo giusto # %%% costruire una immagine WxH di un dato colore slideshow={"slide_type": "fragment"} def crea_immagine(larghezza, altezza, colore=black): return [ [ colore ]*larghezza for i in range(altezza) ] def crea_imm(L,H,C): img = [] for y in range(H): riga = [] for x in range(L): riga.append(C) img.append(riga) return img img = crea_imm(30, 40, red) img[5][7] = blue # coloro un pixel images.visd(img) # e ora va molto meglio # %% [markdown] slideshow={"slide_type": "subslide"} # ## Caricare/salvare una immagine da/su disco # %%% caricare e salvare una immagine con la libreria images slideshow={"slide_type": "fragment"} # Pixel = tuple[int,int,int] # Line = list[Pixel] # Picture = list[Line] # images.load(filename : str) -> Picture img3 = images.load('3cime.png') print(len(img3), len(img3[0])) # altezza e larghezza img3[40][30:250] = [red]*220 # coloriamo una fila di pixel # images.save(img : Picture, filename : str) -> None images.save(img3, '3cime-2.png') images.visd(img3) # %% [markdown] slideshow={"slide_type": "subslide"} # ## Disegnare un pixel # ... senza generare errori se le coordinate sono fuori dall'immagine # %%% evitare di sbordare slideshow={"slide_type": "fragment"} # --- controllando le posizioni def draw_pixel(img, x, y, colore): # ricavo l'altezza e larghezza dell'immagine L,A = len(img[0]), len(img) # cambio il pixel solo se dentro l'immagine if 0 <= x < L and 0 <= y < A: x = int(round(x)) y = int(round(y)) img[y][x] = colore draw_pixel2(img3, 100, 150, red) images.visd(img3) # %% [markdown] slideshow={"slide_type": "subslide"} # ## Try/except/finally # # Per catturare eventuali errori e gestirni nel proprio programma # # ```python # try: # codice che potrebbe produrre un errore # except TipoDiErrore as e: # codice da eseguire se TipoDiErrore # finally: # codice da eseguire alla fine in ogni caso # ``` # %%% evitare di sbordare slideshow={"slide_type": "subslide"} # --- usando try-except per catturare l'errore def draw_pixel(img, x, y, colore): # mi preparo a catturare l'errore (try) try: # disegno il pixel assert x >= 0 and y >= 0 img[y][x] = colore # se c'è errore (except) lo ignoro except IndexError: pass except AssertionError: print('sbordato a sinistra o in alto') pass # --- BEWARE of negative indexes!!! (che non producono errori) # --- BEWARE of generic 'catch-all' except clauses!!!!! (che nascondono TROPPI errori) draw_pixel(img3, -50, -50, red) images.visd(img3) # %% [markdown] slideshow={"slide_type": "slide"} # ## Rotazione di 90° a sinistra (lavagna) # ![](rotazione.png) # %%% ruotare una immagine di 90° in senso anti/orario slideshow={"slide_type": "subslide"} # X_destinazione = y_sorgente # Y_destinazione = larghezza_sorgente - 1 - x_sorgente def ruota_sx(img): altezza = len(img) larghezza = len(img[0]) # creo una immagine con altezza e larghezza scambiate img2 = crea_immagine(altezza, larghezza) # per ogni pixel della immagine originale for y, riga in enumerate(img): for x, pixel in enumerate(riga): # calcolo le coordinate della destinazione X = y Y = larghezza -1 -x # e copio il pixel img2[Y][X] = pixel # torno l'immagine ruotata return img2 img_r = ruota_sx(img3) images.visd(img_r) # --- PER CASA: rotazione destra # %% [markdown] slideshow={"slide_type": "subslide"} # ## Disegnare una linea orizzontale o verticale # %%% Disegnare una retta orizzontale/verticale slideshow={"slide_type": "fragment"} def draw_h_line(img, x, y, x2, colore): # scandisco le X da x a x2 for X in range(x, x2+1): # riusiamo la draw_pixel che controlla di non sbordare draw_pixel(img, X, y, colore) # oppure prima intersechiamo la linea con l'immagine e poi la disegnamo senza controllare def draw_h_line2(img, x, y, x2, colore): larghezza = len(img[0]) altezza = len(img) # se la y è tra 0 e altezza if 0 <= y < altezza: # la parte da disegnare ha estremi non maggiori di larghezza-1 e non minori di 0 x, x2 = min(x,x2), max(x, x2) xmin = max(x, 0) xmax = min(x2, larghezza-1) # una volta aggiustati gli estremi la si disegna for X in range(xmin, xmax+1): img[y][X] = colore img = images.load('3cime.png') draw_h_line2(img, 30, 100, 200, red) images.visd(img) # lo stesso per una linea verticale def draw_v_line(img, x, y, y2, colore): larghezza = len(img[0]) altezza = len(img) # la parte da disegnare ha estremi non maggiori di altezza-1 e non minori di 0 # una volta aggiustati gli estremi la si disegna for Y in range(y, y2+1): # riusiamo la draw_pixel che controlla di non sbordare draw_pixel(img, x, Y, colore) # %% [markdown] slideshow={"slide_type": "subslide"} # ### e per le diagonali? # %%% Disegnare una retta orizzontale/verticale slideshow={"slide_type": "fragment"} # --- e diagonale??? come??? # dipende dalla direzione def draw_slope(img, x1, y1, x2, y2, colore): # FIXME: aggiungere i controlli sulle coordinate? dx = x2-x1 dy = y2-y1 # si varia lungo la direzione più lunga # se |dx| > |dy| ci calcola la y per ciascuna x in [x1 .. x2] # FIXME: e se dx == 0 oppure dy == 0? disegnamo una retta verticale o orizzontale if dx == 0: draw_v_line(img, x1, y1, y2, colore) elif dy == 0: draw_h_line(img, x1, y1, x2, colore) elif abs(dx) >= abs(dy): # mi assicuro che x1