Created
February 5, 2014 20:42
-
-
Save rubik/8832600 to your computer and use it in GitHub Desktop.
Homework04, program01.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'''Definire una classe PColor e una classe PImage secondo le seguenti specifiche. | |
La classe PColor rappresenta un pixel che puo' avere un colore RGB o essere | |
trasparente e deve implementare i seguenti metodi: | |
- Costruttore, senza argomenti, che inizializza l'oggetto come pixel trasparente. | |
- set_RGB(r, g, b) imposta il colore RGB dell'oggetto con i valori r,g,b e | |
ritorna l'oggetto. | |
- to_RGB() ritorna una tripla (r,g,b) che sono i valori dei canali RGB | |
dell'oggetto. Se e' trasparente, ritorna (255,255,255). | |
- set_transparent() imposta l'oggetto come pixel trasparente. | |
- istransparent() ritorna True se l'oggetto e' trasparente, False altrimenti. | |
La classe PImage rappresenta un'immagine che sara' implementata come matrice | |
(lista di liste) di oggetti PColor e deve implementare i seguenti metodi: | |
- Costruttore, con argomento fname, legge dal file fname l'immagine PNG e | |
inizializza l'immagine dell'oggetto con tale immagine. | |
- size() ritorna una coppia (w, h) dove w e h sono la larghezza e l'altezza | |
dell'immagine dell'oggetto. | |
- get_pixel(i, j) ritorna l'oggetto PColor del pixel in posizione (i, j) | |
dell'immagine dell'oggetto. L'oggetto PColor ritornato e' proprio quello | |
usato dall'immagine, per cui modificando questo si modifica l'immagine. | |
- set_transparent(rgbs, t) imposta come trasparenti tutti i pixels dell'immagine | |
dell'oggetto il cui colore e' a distanza al piu' t da uno dei colori (espressi | |
come triple RGB) della lista rgbs. La distanza e' la somma delle differenze | |
assolute delle componenti colore. | |
- copy(pimg, x, y) copia l'immagine pimg (di tipo PImage) sull'immagine | |
dell'oggetto con lo spigolo in alto a sinistra in (x, y). Sono copiati | |
solamente i pixel di pimg che non sono trasparenti. | |
- save(fname) salva l'immagine dell'oggetto nel file fname. | |
Se necessario, si possono aggiungere altri metodi ad entrambe le classi. | |
Per gli esempi vedere il file grade01.txt | |
AVVERTENZE: non usare caratteri non ASCII, come le lettere accentate; | |
non usare moduli che non sono nella libreria standard o non sono forniti | |
nella cartella dell'homework. | |
''' | |
import image # NON MODIFICARE IL MODULO image | |
'''Implementare qui la classe PColor''' | |
class PColor(object): | |
def __init__(self): | |
# Invece che avere piu' attributi sarebbe piu' facile avere solo | |
# channels e settarlo a None per indicare che il pixel e' trasparente. | |
# In questo modo: | |
# self.channels = None | |
self._transparent = False | |
self.channels = (None, None, None) | |
def set_RGB(self, r, g, b): | |
self.channels = (r, g, b) | |
return self | |
def to_RGB(self): | |
# Per le modifiche a __init__ bisogna cambiare questa riga a: | |
# if not self.channels: | |
if self._transparent: | |
return (255, 255, 255) | |
else: | |
return self.channels | |
def set_transparent(self): | |
# Per le modifiche fatte a __init__ bisogna cambiare questa riga a: | |
# self.channels = None | |
self._transparent = True | |
def istransparent(self): | |
# Per le modifiche fatte a __init__ bisogna cambiare questa riga a: | |
# return self.channels == None | |
return self._transparent | |
'''Implementare qui la classe PImage''' | |
def distance(color1, color2): | |
# Questa e' giusta, ed e' uguale alla formula del professore, solo piu' | |
# concisa. | |
return sum(abs(a - b) for a, b in zip(color1, color2)) | |
class PImage(object): | |
def __init__(self, fname): | |
# Questo e' tutto giusto. | |
# Questa e' una doppia list comprehension: | |
# http://docs.python.org/2/tutorial/datastructures.html#list-comprehensions | |
self.image = [[PColor().set_RGB(*p) for p in row] for row in \ | |
image.load(fname)] | |
def size(self): | |
return (len(self.image[0]), len(self.image)) | |
def get_pixel(self, i, j): | |
return self.image[j][i] | |
def set_transparent(self, rgbs, t): | |
for row in self.image: | |
for pixel in row: | |
# Se si controlla se il pixel e' gia' trasparente si ottimizza | |
# il programma: | |
# if pixel.istransparent(): continue | |
# Qui e' sbagliato. Dovrebbe essere: | |
# if min(rgbs, key=lambda c: distance(pixel.to_RGB(), c)) <= t: | |
# perche' basta che una delle distanze sia minore di t per | |
# settare il pixel come trasparente. | |
# La funzione min() applica la funzione key ad ogni elemento | |
# della lista: | |
# http://docs.python.org/2/library/functions.html#min | |
if max(rgbs, lambda c: distance(pixel.get_RGB(), c)) < t: | |
pixel.set_transparent() | |
def copy(self, pimg, x, y): | |
w, h = pimg.size() | |
dst = self.image | |
src = pimg.image | |
for j in range(h): | |
for i in range(w): | |
# Le prossime 5 righe sono molto complesse e potrebbero essere | |
# piu' facilmente riscritte nel modo seguente. | |
# di, dj = i + x, j + y | |
# pc = pimg.get_pixel(i, j) | |
# if image.inside(src, di, dj) and not pc.istransparent(): | |
# src.get_pixel(di, dj).set_RGB(*pc.to_RGB()) | |
di, dj = i+x, j+y | |
si, sj = i, j # Questa riga e' inutile | |
if (image.inside(dst, di, dj) and image.inside(src, si, sj) | |
and not pimg.get_pixel(si, sj).istransparent): | |
# Questo modo di settare il pixel e' assolutamente | |
# sbagliato, perche' lo setta in dst, mentre dovrebbe | |
# settarlo in src. | |
dst[dj][di] = src[sj][si] | |
def save(self, fname): | |
# Questo e' tutto giusto | |
image.save(fname, [[color.to_RGB() for color in row] for row in self.image]) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment