Skip to content

Instantly share code, notes, and snippets.

@rubik
Created February 5, 2014 20:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rubik/8832600 to your computer and use it in GitHub Desktop.
Save rubik/8832600 to your computer and use it in GitHub Desktop.
Homework04, program01.py
'''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